diff options
author | robot-dts-analyst <robot-dts-analyst@yandex-team.com> | 2022-09-26 10:57:34 +0300 |
---|---|---|
committer | robot-dts-analyst <robot-dts-analyst@yandex-team.com> | 2022-09-26 10:57:34 +0300 |
commit | c18f43134924a1f221c65caae777fa4ea68ee42f (patch) | |
tree | 5b3e5f4dad2e37b4a8fbfd78011c60e453a70322 /contrib | |
parent | 861d329b972f5db9d1cce78ba43bced3cb2bb06e (diff) | |
download | ydb-c18f43134924a1f221c65caae777fa4ea68ee42f.tar.gz |
Rebalancing autocheck partitions and distbuild clusters.
The process of preparing changes https://sandbox.yandex-team.ru/task/1461772447/view
Diffstat (limited to 'contrib')
82 files changed, 18216 insertions, 0 deletions
diff --git a/contrib/libs/curl/src/slist_wc.c b/contrib/libs/curl/src/slist_wc.c new file mode 100644 index 0000000000..68021e61e0 --- /dev/null +++ b/contrib/libs/curl/src/slist_wc.c @@ -0,0 +1,74 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "tool_setup.h" + +#ifndef CURL_DISABLE_LIBCURL_OPTION + +#include "slist_wc.h" + +/* The last #include files should be: */ +#include "memdebug.h" + +/* + * slist_wc_append() appends a string to the linked list. This function can be + * used as an initialization function as well as an append function. + */ +struct slist_wc *slist_wc_append(struct slist_wc *list, + const char *data) +{ + struct curl_slist *new_item = curl_slist_append(NULL, data); + + if(!new_item) + return NULL; + + if(!list) { + list = malloc(sizeof(struct slist_wc)); + + if(!list) { + curl_slist_free_all(new_item); + return NULL; + } + + list->first = new_item; + list->last = new_item; + return list; + } + + list->last->next = new_item; + list->last = list->last->next; + return list; +} + +/* be nice and clean up resources */ +void slist_wc_free_all(struct slist_wc *list) +{ + if(!list) + return; + + curl_slist_free_all(list->first); + free(list); +} + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ diff --git a/contrib/libs/curl/src/slist_wc.h b/contrib/libs/curl/src/slist_wc.h new file mode 100644 index 0000000000..e309fd5a36 --- /dev/null +++ b/contrib/libs/curl/src/slist_wc.h @@ -0,0 +1,57 @@ +#ifndef HEADER_CURL_SLIST_WC_H +#define HEADER_CURL_SLIST_WC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "tool_setup.h" +#ifndef CURL_DISABLE_LIBCURL_OPTION + +/* linked-list structure with last node cache for easysrc */ +struct slist_wc { + struct curl_slist *first; + struct curl_slist *last; +}; + +/* + * NAME curl_slist_wc_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +struct slist_wc *slist_wc_append(struct slist_wc *, const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist_wc. + */ +void slist_wc_free_all(struct slist_wc *); + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ + +#endif /* HEADER_CURL_SLIST_WC_H */ diff --git a/contrib/libs/curl/src/tool_binmode.c b/contrib/libs/curl/src/tool_binmode.c new file mode 100644 index 0000000000..68c6c36716 --- /dev/null +++ b/contrib/libs/curl/src/tool_binmode.c @@ -0,0 +1,53 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_SETMODE + +#ifdef HAVE_IO_H +# include <io.h> +#endif + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#include "tool_binmode.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void set_binmode(FILE *stream) +{ +#ifdef O_BINARY +# ifdef __HIGHC__ + _setmode(stream, O_BINARY); +# else + (void)setmode(fileno(stream), O_BINARY); +# endif +#else + (void)stream; +#endif +} + +#endif /* HAVE_SETMODE */ diff --git a/contrib/libs/curl/src/tool_binmode.h b/contrib/libs/curl/src/tool_binmode.h new file mode 100644 index 0000000000..0b3d24b389 --- /dev/null +++ b/contrib/libs/curl/src/tool_binmode.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_TOOL_BINMODE_H +#define HEADER_CURL_TOOL_BINMODE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_SETMODE + +void set_binmode(FILE *stream); + +#else + +#define set_binmode(x) Curl_nop_stmt + +#endif /* HAVE_SETMODE */ + +#endif /* HEADER_CURL_TOOL_BINMODE_H */ diff --git a/contrib/libs/curl/src/tool_bname.c b/contrib/libs/curl/src/tool_bname.c new file mode 100644 index 0000000000..e70f7d76ff --- /dev/null +++ b/contrib/libs/curl/src/tool_bname.c @@ -0,0 +1,51 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "tool_bname.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifndef HAVE_BASENAME + +char *tool_basename(char *path) +{ + char *s1; + char *s2; + + s1 = strrchr(path, '/'); + s2 = strrchr(path, '\\'); + + if(s1 && s2) { + path = (s1 > s2) ? s1 + 1 : s2 + 1; + } + else if(s1) + path = s1 + 1; + else if(s2) + path = s2 + 1; + + return path; +} + +#endif /* HAVE_BASENAME */ diff --git a/contrib/libs/curl/src/tool_bname.h b/contrib/libs/curl/src/tool_bname.h new file mode 100644 index 0000000000..0efd7f19cb --- /dev/null +++ b/contrib/libs/curl/src/tool_bname.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_BNAME_H +#define HEADER_CURL_TOOL_BNAME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifndef HAVE_BASENAME + +char *tool_basename(char *path); + +#define basename(x) tool_basename((x)) + +#endif /* HAVE_BASENAME */ + +#endif /* HEADER_CURL_TOOL_BNAME_H */ diff --git a/contrib/libs/curl/src/tool_cb_dbg.c b/contrib/libs/curl/src/tool_cb_dbg.c new file mode 100644 index 0000000000..c1dba85ab8 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_dbg.c @@ -0,0 +1,248 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_cb_dbg.h" +#include "tool_util.h" + +#include "memdebug.h" /* keep this as LAST include */ + +static void dump(const char *timebuf, const char *text, + FILE *stream, const unsigned char *ptr, size_t size, + trace tracetype, curl_infotype infotype); + +/* +** callback for CURLOPT_DEBUGFUNCTION +*/ + +int tool_debug_cb(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userdata) +{ + struct OperationConfig *operation = userdata; + struct GlobalConfig *config = operation->global; + FILE *output = config->errors; + const char *text; + struct timeval tv; + char timebuf[20]; + time_t secs; + + (void)handle; /* not used */ + + if(config->tracetime) { + struct tm *now; + static time_t epoch_offset; + static int known_offset; + tv = tvnow(); + if(!known_offset) { + epoch_offset = time(NULL) - tv.tv_sec; + known_offset = 1; + } + secs = epoch_offset + tv.tv_sec; + /* !checksrc! disable BANNEDFUNC 1 */ + now = localtime(&secs); /* not thread safe but we don't care */ + msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ", + now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); + } + else + timebuf[0] = 0; + + if(!config->trace_stream) { + /* open for append */ + if(!strcmp("-", config->trace_dump)) + config->trace_stream = stdout; + else if(!strcmp("%", config->trace_dump)) + /* Ok, this is somewhat hackish but we do it undocumented for now */ + config->trace_stream = config->errors; /* aka stderr */ + else { + config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT); + config->trace_fopened = TRUE; + } + } + + if(config->trace_stream) + output = config->trace_stream; + + if(!output) { + warnf(config, "Failed to create/open output"); + return 0; + } + + if(config->tracetype == TRACE_PLAIN) { + /* + * This is the trace look that is similar to what libcurl makes on its + * own. + */ + static const char * const s_infotype[] = { + "*", "<", ">", "{", "}", "{", "}" + }; + static bool newl = FALSE; + static bool traced_data = FALSE; + + switch(type) { + case CURLINFO_HEADER_OUT: + if(size > 0) { + size_t st = 0; + size_t i; + for(i = 0; i < size - 1; i++) { + if(data[i] == '\n') { /* LF */ + if(!newl) { + fprintf(output, "%s%s ", timebuf, s_infotype[type]); + } + (void)fwrite(data + st, i - st + 1, 1, output); + st = i + 1; + newl = FALSE; + } + } + if(!newl) + fprintf(output, "%s%s ", timebuf, s_infotype[type]); + (void)fwrite(data + st, i - st + 1, 1, output); + } + newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; + traced_data = FALSE; + break; + case CURLINFO_TEXT: + case CURLINFO_HEADER_IN: + if(!newl) + fprintf(output, "%s%s ", timebuf, s_infotype[type]); + (void)fwrite(data, size, 1, output); + newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE; + traced_data = FALSE; + break; + case CURLINFO_DATA_OUT: + case CURLINFO_DATA_IN: + case CURLINFO_SSL_DATA_IN: + case CURLINFO_SSL_DATA_OUT: + if(!traced_data) { + /* if the data is output to a tty and we're sending this debug trace + to stderr or stdout, we don't display the alert about the data not + being shown as the data _is_ shown then just not via this + function */ + if(!config->isatty || ((output != stderr) && (output != stdout))) { + if(!newl) + fprintf(output, "%s%s ", timebuf, s_infotype[type]); + fprintf(output, "[%zu bytes data]\n", size); + newl = FALSE; + traced_data = TRUE; + } + } + break; + default: /* nada */ + newl = FALSE; + traced_data = FALSE; + break; + } + + return 0; + } + + switch(type) { + case CURLINFO_TEXT: + fprintf(output, "%s== Info: %.*s", timebuf, (int)size, data); + /* FALLTHROUGH */ + default: /* in case a new one is introduced to shock us */ + return 0; + + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + } + + dump(timebuf, text, output, (unsigned char *) data, size, config->tracetype, + type); + return 0; +} + +static void dump(const char *timebuf, const char *text, + FILE *stream, const unsigned char *ptr, size_t size, + trace tracetype, curl_infotype infotype) +{ + size_t i; + size_t c; + + unsigned int width = 0x10; + + if(tracetype == TRACE_ASCII) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stream, "%s%s, %zu bytes (0x%zx)\n", timebuf, text, size, size); + + for(i = 0; i < size; i += width) { + + fprintf(stream, "%04zx: ", i); + + if(tracetype == TRACE_BIN) { + /* hex not disabled, show it */ + for(c = 0; c < width; c++) + if(i + c < size) + fprintf(stream, "%02x ", ptr[i + c]); + else + fputs(" ", stream); + } + + for(c = 0; (c < width) && (i + c < size); c++) { + /* check for 0D0A; if found, skip past and start a new line of output */ + if((tracetype == TRACE_ASCII) && + (i + c + 1 < size) && (ptr[i + c] == 0x0D) && + (ptr[i + c + 1] == 0x0A)) { + i += (c + 2 - width); + break; + } + (void)infotype; + fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ? + ptr[i + c] : UNPRINTABLE_CHAR); + /* check again for 0D0A, to avoid an extra \n if it's at width */ + if((tracetype == TRACE_ASCII) && + (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) && + (ptr[i + c + 2] == 0x0A)) { + i += (c + 3 - width); + break; + } + } + fputc('\n', stream); /* newline */ + } + fflush(stream); +} diff --git a/contrib/libs/curl/src/tool_cb_dbg.h b/contrib/libs/curl/src/tool_cb_dbg.h new file mode 100644 index 0000000000..bc69e56604 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_dbg.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_CB_DBG_H +#define HEADER_CURL_TOOL_CB_DBG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* +** callback for CURLOPT_DEBUGFUNCTION +*/ + +int tool_debug_cb(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userdata); + +#endif /* HEADER_CURL_TOOL_CB_DBG_H */ diff --git a/contrib/libs/curl/src/tool_cb_hdr.c b/contrib/libs/curl/src/tool_cb_hdr.c new file mode 100644 index 0000000000..64b2bb212f --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_hdr.c @@ -0,0 +1,415 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_doswin.h" +#include "tool_msgs.h" +#include "tool_cb_hdr.h" +#include "tool_cb_wrt.h" +#include "tool_operate.h" + +#include "memdebug.h" /* keep this as LAST include */ + +static char *parse_filename(const char *ptr, size_t len); + +#ifdef WIN32 +#define BOLD +#define BOLDOFF +#else +#define BOLD "\x1b[1m" +/* Switch off bold by setting "all attributes off" since the explicit + bold-off code (21) isn't supported everywhere - like in the mac + Terminal. */ +#define BOLDOFF "\x1b[0m" +/* OSC 8 hyperlink escape sequence */ +#define LINK "\x1b]8;;" +#define LINKST "\x1b\\" +#define LINKOFF LINK LINKST +#endif + +#ifdef LINK +static void write_linked_location(CURL *curl, const char *location, + size_t loclen, FILE *stream); +#endif + +/* +** callback for CURLOPT_HEADERFUNCTION +*/ + +size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + struct per_transfer *per = userdata; + struct HdrCbData *hdrcbdata = &per->hdrcbdata; + struct OutStruct *outs = &per->outs; + struct OutStruct *heads = &per->heads; + struct OutStruct *etag_save = &per->etag_save; + const char *str = ptr; + const size_t cb = size * nmemb; + const char *end = (char *)ptr + cb; + long protocol = 0; + + /* + * Once that libcurl has called back tool_header_cb() the returned value + * is checked against the amount that was intended to be written, if + * it does not match then it fails with CURLE_WRITE_ERROR. So at this + * point returning a value different from sz*nmemb indicates failure. + */ + size_t failure = (size && nmemb) ? 0 : 1; + + if(!per->config) + return failure; + +#ifdef DEBUGBUILD + if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { + warnf(per->config->global, "Header data exceeds single call write " + "limit!\n"); + return failure; + } +#endif + + /* + * Write header data when curl option --dump-header (-D) is given. + */ + + if(per->config->headerfile && heads->stream) { + size_t rc = fwrite(ptr, size, nmemb, heads->stream); + if(rc != cb) + return rc; + /* flush the stream to send off what we got earlier */ + (void)fflush(heads->stream); + } + + /* + * Write etag to file when --etag-save option is given. + */ + if(per->config->etag_save_file && etag_save->stream) { + /* match only header that start with etag (case insensitive) */ + if(curl_strnequal(str, "etag:", 5)) { + const char *etag_h = &str[5]; + const char *eot = end - 1; + if(*eot == '\n') { + while(ISSPACE(*etag_h) && (etag_h < eot)) + etag_h++; + while(ISSPACE(*eot)) + eot--; + + if(eot >= etag_h) { + size_t etag_length = eot - etag_h + 1; + fwrite(etag_h, size, etag_length, etag_save->stream); + /* terminate with newline */ + fputc('\n', etag_save->stream); + (void)fflush(etag_save->stream); + } + } + } + } + + /* + * This callback sets the filename where output shall be written when + * curl options --remote-name (-O) and --remote-header-name (-J) have + * been simultaneously given and additionally server returns an HTTP + * Content-Disposition header specifying a filename property. + */ + + curl_easy_getinfo(per->curl, CURLINFO_PROTOCOL, &protocol); + if(hdrcbdata->honor_cd_filename && + (cb > 20) && checkprefix("Content-disposition:", str) && + (protocol & (CURLPROTO_HTTPS|CURLPROTO_HTTP))) { + const char *p = str + 20; + + /* look for the 'filename=' parameter + (encoded filenames (*=) are not supported) */ + for(;;) { + char *filename; + size_t len; + + while(*p && (p < end) && !ISALPHA(*p)) + p++; + if(p > end - 9) + break; + + if(memcmp(p, "filename=", 9)) { + /* no match, find next parameter */ + while((p < end) && (*p != ';')) + p++; + continue; + } + p += 9; + + /* this expression below typecasts 'cb' only to avoid + warning: signed and unsigned type in conditional expression + */ + len = (ssize_t)cb - (p - str); + filename = parse_filename(p, len); + if(filename) { + if(outs->stream) { + /* indication of problem, get out! */ + free(filename); + return failure; + } + + outs->is_cd_filename = TRUE; + outs->s_isreg = TRUE; + outs->fopened = FALSE; + outs->filename = filename; + outs->alloc_filename = TRUE; + hdrcbdata->honor_cd_filename = FALSE; /* done now! */ + if(!tool_create_output_file(outs, per->config)) + return failure; + } + break; + } + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return failure; + } + if(hdrcbdata->config->writeout) { + char *value = memchr(ptr, ':', cb); + if(value) { + if(per->was_last_header_empty) + per->num_headers = 0; + per->was_last_header_empty = FALSE; + per->num_headers++; + } + else if(ptr[0] == '\r' || ptr[0] == '\n') + per->was_last_header_empty = TRUE; + } + if(hdrcbdata->config->show_headers && + (protocol & + (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_RTSP|CURLPROTO_FILE))) { + /* bold headers only for selected protocols */ + char *value = NULL; + + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return failure; + + if(hdrcbdata->global->isatty && hdrcbdata->global->styled_output) + value = memchr(ptr, ':', cb); + if(value) { + size_t namelen = value - ptr; + fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", namelen, ptr); +#ifndef LINK + fwrite(&value[1], cb - namelen - 1, 1, outs->stream); +#else + if(curl_strnequal("Location", ptr, namelen)) { + write_linked_location(per->curl, &value[1], cb - namelen - 1, + outs->stream); + } + else + fwrite(&value[1], cb - namelen - 1, 1, outs->stream); +#endif + } + else + /* not "handled", just show it */ + fwrite(ptr, cb, 1, outs->stream); + } + return cb; +} + +/* + * Copies a file name part and returns an ALLOCATED data buffer. + */ +static char *parse_filename(const char *ptr, size_t len) +{ + char *copy; + char *p; + char *q; + char stop = '\0'; + + /* simple implementation of strndup() */ + copy = malloc(len + 1); + if(!copy) + return NULL; + memcpy(copy, ptr, len); + copy[len] = '\0'; + + p = copy; + if(*p == '\'' || *p == '"') { + /* store the starting quote */ + stop = *p; + p++; + } + else + stop = ';'; + + /* scan for the end letter and stop there */ + q = strchr(p, stop); + if(q) + *q = '\0'; + + /* if the filename contains a path, only use filename portion */ + q = strrchr(p, '/'); + if(q) { + p = q + 1; + if(!*p) { + Curl_safefree(copy); + return NULL; + } + } + + /* If the filename contains a backslash, only use filename portion. The idea + is that even systems that don't handle backslashes as path separators + probably want the path removed for convenience. */ + q = strrchr(p, '\\'); + if(q) { + p = q + 1; + if(!*p) { + Curl_safefree(copy); + return NULL; + } + } + + /* make sure the file name doesn't end in \r or \n */ + q = strchr(p, '\r'); + if(q) + *q = '\0'; + + q = strchr(p, '\n'); + if(q) + *q = '\0'; + + if(copy != p) + memmove(copy, p, strlen(p) + 1); + +#if defined(MSDOS) || defined(WIN32) + { + char *sanitized; + SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0); + Curl_safefree(copy); + if(sc) + return NULL; + copy = sanitized; + } +#endif /* MSDOS || WIN32 */ + + /* in case we built debug enabled, we allow an environment variable + * named CURL_TESTDIR to prefix the given file name to put it into a + * specific directory + */ +#ifdef DEBUGBUILD + { + char *tdir = curlx_getenv("CURL_TESTDIR"); + if(tdir) { + char buffer[512]; /* suitably large */ + msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy); + Curl_safefree(copy); + copy = strdup(buffer); /* clone the buffer, we don't use the libcurl + aprintf() or similar since we want to use the + same memory code as the "real" parse_filename + function */ + curl_free(tdir); + } + } +#endif + + return copy; +} + +#ifdef LINK +/* + * Treat the Location: header specially, by writing a special escape + * sequence that adds a hyperlink to the displayed text. This makes + * the absolute URL of the redirect clickable in supported terminals, + * which couldn't happen otherwise for relative URLs. The Location: + * header is supposed to always be absolute so this theoretically + * shouldn't be needed but the real world returns plenty of relative + * URLs here. + */ +static +void write_linked_location(CURL *curl, const char *location, size_t loclen, + FILE *stream) { + /* This would so simple if CURLINFO_REDIRECT_URL were available here */ + CURLU *u = NULL; + char *copyloc = NULL, *locurl = NULL, *scheme = NULL, *finalurl = NULL; + const char *loc = location; + size_t llen = loclen; + + /* Strip leading whitespace of the redirect URL */ + while(llen && *loc == ' ') { + ++loc; + --llen; + } + + /* Strip the trailing end-of-line characters, normally "\r\n" */ + while(llen && (loc[llen-1] == '\n' || loc[llen-1] == '\r')) + --llen; + + /* CURLU makes it easy to handle the relative URL case */ + u = curl_url(); + if(!u) + goto locout; + + /* Create a NUL-terminated and whitespace-stripped copy of Location: */ + copyloc = malloc(llen + 1); + if(!copyloc) + goto locout; + memcpy(copyloc, loc, llen); + copyloc[llen] = 0; + + /* The original URL to use as a base for a relative redirect URL */ + if(curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &locurl)) + goto locout; + if(curl_url_set(u, CURLUPART_URL, locurl, 0)) + goto locout; + + /* Redirected location. This can be either absolute or relative. */ + if(curl_url_set(u, CURLUPART_URL, copyloc, 0)) + goto locout; + + if(curl_url_get(u, CURLUPART_URL, &finalurl, CURLU_NO_DEFAULT_PORT)) + goto locout; + + if(curl_url_get(u, CURLUPART_SCHEME, &scheme, 0)) + goto locout; + + if(!strcmp("http", scheme) || + !strcmp("https", scheme) || + !strcmp("ftp", scheme) || + !strcmp("ftps", scheme)) { + fprintf(stream, LINK "%s" LINKST "%.*s" LINKOFF, + finalurl, loclen, location); + goto locdone; + } + + /* Not a "safe" URL: don't linkify it */ + +locout: + /* Write the normal output in case of error or unsafe */ + fwrite(location, loclen, 1, stream); + +locdone: + if(u) { + curl_free(finalurl); + curl_free(scheme); + curl_url_cleanup(u); + free(copyloc); + } +} +#endif diff --git a/contrib/libs/curl/src/tool_cb_hdr.h b/contrib/libs/curl/src/tool_cb_hdr.h new file mode 100644 index 0000000000..01175bb6ab --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_hdr.h @@ -0,0 +1,58 @@ +#ifndef HEADER_CURL_TOOL_CB_HDR_H +#define HEADER_CURL_TOOL_CB_HDR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* + * curl operates using a single HdrCbData struct variable, a + * pointer to this is passed as userdata pointer to tool_header_cb. + * + * 'outs' member is a pointer to the OutStruct variable used to keep + * track of information relative to curl's output writing. + * + * 'heads' member is a pointer to the OutStruct variable used to keep + * track of information relative to header response writing. + * + * 'honor_cd_filename' member is TRUE when tool_header_cb is allowed + * to honor Content-Disposition filename property and accordingly + * set 'outs' filename, otherwise FALSE; + */ + +struct HdrCbData { + struct GlobalConfig *global; + struct OperationConfig *config; + struct OutStruct *outs; + struct OutStruct *heads; + struct OutStruct *etag_save; + bool honor_cd_filename; +}; + +/* +** callback for CURLOPT_HEADERFUNCTION +*/ + +size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata); + +#endif /* HEADER_CURL_TOOL_CB_HDR_H */ diff --git a/contrib/libs/curl/src/tool_cb_prg.c b/contrib/libs/curl/src/tool_cb_prg.c new file mode 100644 index 0000000000..3532c31bc1 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_prg.c @@ -0,0 +1,280 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_cb_prg.h" +#include "tool_util.h" +#include "tool_operate.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef HAVE_TERMIOS_H +# include <termios.h> +#elif defined(HAVE_TERMIO_H) +# include <termio.h> +#endif + +/* 200 values generated by this perl code: + + my $pi = 3.1415; + foreach my $i (1 .. 200) { + printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000; + } +*/ +static const unsigned int sinus[] = { + 515704, 531394, 547052, 562664, 578214, 593687, 609068, 624341, 639491, + 654504, 669364, 684057, 698568, 712883, 726989, 740870, 754513, 767906, + 781034, 793885, 806445, 818704, 830647, 842265, 853545, 864476, 875047, + 885248, 895069, 904500, 913532, 922156, 930363, 938145, 945495, 952406, + 958870, 964881, 970434, 975522, 980141, 984286, 987954, 991139, 993840, + 996054, 997778, 999011, 999752, 999999, 999754, 999014, 997783, 996060, + 993848, 991148, 987964, 984298, 980154, 975536, 970449, 964898, 958888, + 952426, 945516, 938168, 930386, 922180, 913558, 904527, 895097, 885277, + 875077, 864507, 853577, 842299, 830682, 818739, 806482, 793922, 781072, + 767945, 754553, 740910, 727030, 712925, 698610, 684100, 669407, 654548, + 639536, 624386, 609113, 593733, 578260, 562710, 547098, 531440, 515751, + 500046, 484341, 468651, 452993, 437381, 421830, 406357, 390976, 375703, + 360552, 345539, 330679, 315985, 301474, 287158, 273052, 259170, 245525, + 232132, 219003, 206152, 193590, 181331, 169386, 157768, 146487, 135555, + 124983, 114781, 104959, 95526, 86493, 77868, 69660, 61876, 54525, 47613, + 41147, 35135, 29581, 24491, 19871, 15724, 12056, 8868, 6166, 3951, 2225, + 990, 248, 0, 244, 982, 2212, 3933, 6144, 8842, 12025, 15690, 19832, 24448, + 29534, 35084, 41092, 47554, 54462, 61809, 69589, 77794, 86415, 95445, + 104873, 114692, 124891, 135460, 146389, 157667, 169282, 181224, 193480, + 206039, 218888, 232015, 245406, 259048, 272928, 287032, 301346, 315856, + 330548, 345407, 360419, 375568, 390841, 406221, 421693, 437243, 452854, + 468513, 484202, 499907 +}; + +static void fly(struct ProgressData *bar, bool moved) +{ + char buf[256]; + int pos; + int check = bar->width - 2; + + msnprintf(buf, sizeof(buf), "%*s\r", bar->width-1, " "); + memcpy(&buf[bar->bar], "-=O=-", 5); + + pos = sinus[bar->tick%200] / (1000000 / check); + buf[pos] = '#'; + pos = sinus[(bar->tick + 5)%200] / (1000000 / check); + buf[pos] = '#'; + pos = sinus[(bar->tick + 10)%200] / (1000000 / check); + buf[pos] = '#'; + pos = sinus[(bar->tick + 15)%200] / (1000000 / check); + buf[pos] = '#'; + + fputs(buf, bar->out); + bar->tick += 2; + if(bar->tick >= 200) + bar->tick -= 200; + + bar->bar += (moved?bar->barmove:0); + if(bar->bar >= (bar->width - 6)) { + bar->barmove = -1; + bar->bar = bar->width - 6; + } + else if(bar->bar < 0) { + bar->barmove = 1; + bar->bar = 0; + } +} + +/* +** callback for CURLOPT_XFERINFOFUNCTION +*/ + +#define MAX_BARLENGTH 256 + +#if (SIZEOF_CURL_OFF_T == 4) +# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF) +#else + /* assume SIZEOF_CURL_OFF_T == 8 */ +# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) +#endif + +int tool_progress_cb(void *clientp, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) +{ + struct timeval now = tvnow(); + struct per_transfer *per = clientp; + struct OperationConfig *config = per->config; + struct ProgressData *bar = &per->progressbar; + curl_off_t total; + curl_off_t point; + + /* Calculate expected transfer size. initial_size can be less than zero when + indicating that we are expecting to get the filesize from the remote */ + if(bar->initial_size < 0) { + if(dltotal || ultotal) + total = dltotal + ultotal; + else + total = CURL_OFF_T_MAX; + } + else if((CURL_OFF_T_MAX - bar->initial_size) < (dltotal + ultotal)) + total = CURL_OFF_T_MAX; + else + total = dltotal + ultotal + bar->initial_size; + + /* Calculate the current progress. initial_size can be less than zero when + indicating that we are expecting to get the filesize from the remote */ + if(bar->initial_size < 0) { + if(dltotal || ultotal) + point = dlnow + ulnow; + else + point = CURL_OFF_T_MAX; + } + else if((CURL_OFF_T_MAX - bar->initial_size) < (dlnow + ulnow)) + point = CURL_OFF_T_MAX; + else + point = dlnow + ulnow + bar->initial_size; + + if(bar->calls) { + /* after first call... */ + if(total) { + /* we know the total data to get... */ + if(bar->prev == point) + /* progress didn't change since last invoke */ + return 0; + else if((tvdiff(now, bar->prevtime) < 100L) && point < total) + /* limit progress-bar updating to 10 Hz except when we're at 100% */ + return 0; + } + else { + /* total is unknown */ + if(tvdiff(now, bar->prevtime) < 100L) + /* limit progress-bar updating to 10 Hz */ + return 0; + fly(bar, point != bar->prev); + } + } + + /* simply count invokes */ + bar->calls++; + + if((total > 0) && (point != bar->prev)) { + char line[MAX_BARLENGTH + 1]; + char format[40]; + double frac; + double percent; + int barwidth; + int num; + if(point > total) + /* we have got more than the expected total! */ + total = point; + + frac = (double)point / (double)total; + percent = frac * 100.0; + barwidth = bar->width - 7; + num = (int) (((double)barwidth) * frac); + if(num > MAX_BARLENGTH) + num = MAX_BARLENGTH; + memset(line, '#', num); + line[num] = '\0'; + msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth); + fprintf(bar->out, format, line, percent); + } + fflush(bar->out); + bar->prev = point; + bar->prevtime = now; + + if(config->readbusy) { + config->readbusy = FALSE; + curl_easy_pause(per->curl, CURLPAUSE_CONT); + } + + return 0; +} + +void progressbarinit(struct ProgressData *bar, + struct OperationConfig *config) +{ + char *colp; + memset(bar, 0, sizeof(struct ProgressData)); + + /* pass the resume from value through to the progress function so it can + * display progress towards total file not just the part that's left. */ + if(config->use_resume) + bar->initial_size = config->resume_from; + + colp = curlx_getenv("COLUMNS"); + if(colp) { + char *endptr; + long num = strtol(colp, &endptr, 10); + if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) && + (num < 10000)) + bar->width = (int)num; + curl_free(colp); + } + + if(!bar->width) { + int cols = 0; + +#ifdef TIOCGSIZE + struct ttysize ts; + if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts)) + cols = ts.ts_cols; +#elif defined(TIOCGWINSZ) + struct winsize ts; + if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts)) + cols = ts.ws_col; +#elif defined(WIN32) + { + HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO console_info; + + if((stderr_hnd != INVALID_HANDLE_VALUE) && + GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) { + /* + * Do not use +1 to get the true screen-width since writing a + * character at the right edge will cause a line wrap. + */ + cols = (int) + (console_info.srWindow.Right - console_info.srWindow.Left); + } + } +#endif /* TIOCGSIZE */ + if(cols > 20) + bar->width = cols; + } + + if(!bar->width) + bar->width = 79; + else if(bar->width > MAX_BARLENGTH) + bar->width = MAX_BARLENGTH; + + bar->out = config->global->errors; + bar->tick = 150; + bar->barmove = 1; +} diff --git a/contrib/libs/curl/src/tool_cb_prg.h b/contrib/libs/curl/src/tool_cb_prg.h new file mode 100644 index 0000000000..7d8fbae8f9 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_prg.h @@ -0,0 +1,54 @@ +#ifndef HEADER_CURL_TOOL_CB_PRG_H +#define HEADER_CURL_TOOL_CB_PRG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define CURL_PROGRESS_STATS 0 /* default progress display */ +#define CURL_PROGRESS_BAR 1 + +struct ProgressData { + int calls; + curl_off_t prev; + struct timeval prevtime; + int width; + FILE *out; /* where to write everything to */ + curl_off_t initial_size; + unsigned int tick; + int bar; + int barmove; +}; + +void progressbarinit(struct ProgressData *bar, + struct OperationConfig *config); + +/* +** callback for CURLOPT_PROGRESSFUNCTION +*/ + +int tool_progress_cb(void *clientp, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow); + +#endif /* HEADER_CURL_TOOL_CB_PRG_H */ diff --git a/contrib/libs/curl/src/tool_cb_rea.c b/contrib/libs/curl/src/tool_cb_rea.c new file mode 100644 index 0000000000..4aed55c3aa --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_rea.c @@ -0,0 +1,81 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_cb_rea.h" +#include "tool_operate.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* +** callback for CURLOPT_READFUNCTION +*/ + +size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) +{ + ssize_t rc; + struct InStruct *in = userdata; + + rc = read(in->fd, buffer, sz*nmemb); + if(rc < 0) { + if(errno == EAGAIN) { + errno = 0; + in->config->readbusy = TRUE; + return CURL_READFUNC_PAUSE; + } + /* since size_t is unsigned we can't return negative values fine */ + rc = 0; + } + in->config->readbusy = FALSE; + return (size_t)rc; +} + +/* +** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads +*/ + +int tool_readbusy_cb(void *clientp, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) +{ + struct per_transfer *per = clientp; + struct OperationConfig *config = per->config; + + (void)dltotal; /* unused */ + (void)dlnow; /* unused */ + (void)ultotal; /* unused */ + (void)ulnow; /* unused */ + + if(config->readbusy) { + config->readbusy = FALSE; + curl_easy_pause(per->curl, CURLPAUSE_CONT); + } + + return per->noprogress? 0 : CURL_PROGRESSFUNC_CONTINUE; +} diff --git a/contrib/libs/curl/src/tool_cb_rea.h b/contrib/libs/curl/src/tool_cb_rea.h new file mode 100644 index 0000000000..81b5f871a5 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_rea.h @@ -0,0 +1,42 @@ +#ifndef HEADER_CURL_TOOL_CB_REA_H +#define HEADER_CURL_TOOL_CB_REA_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* +** callback for CURLOPT_READFUNCTION +*/ + +size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata); + +/* +** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads +*/ + +int tool_readbusy_cb(void *clientp, + curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow); + +#endif /* HEADER_CURL_TOOL_CB_REA_H */ diff --git a/contrib/libs/curl/src/tool_cb_see.c b/contrib/libs/curl/src/tool_cb_see.c new file mode 100644 index 0000000000..d24d526518 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_see.c @@ -0,0 +1,135 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_cb_see.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* OUR_MAX_SEEK_L has 'long' data type, OUR_MAX_SEEK_O has 'curl_off_t, + both represent the same value. Maximum offset used here when we lseek + using a 'long' data type offset */ + +#define OUR_MAX_SEEK_L 2147483647L - 1L +#define OUR_MAX_SEEK_O CURL_OFF_T_C(0x7FFFFFFF) - CURL_OFF_T_C(0x1) + +/* +** callback for CURLOPT_SEEKFUNCTION +** +** Notice that this is not supposed to return the resulting offset. This +** shall only return CURL_SEEKFUNC_* return codes. +*/ + +int tool_seek_cb(void *userdata, curl_off_t offset, int whence) +{ + struct InStruct *in = userdata; + +#if(SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES) + + /* The offset check following here is only interesting if curl_off_t is + larger than off_t and we are not using the WIN32 large file support + macros that provide the support to do 64bit seeks correctly */ + + if(offset > OUR_MAX_SEEK_O) { + /* Some precaution code to work around problems with different data sizes + to allow seeking >32bit even if off_t is 32bit. Should be very rare and + is really valid on weirdo-systems. */ + curl_off_t left = offset; + + if(whence != SEEK_SET) + /* this code path doesn't support other types */ + return CURL_SEEKFUNC_FAIL; + + if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET)) + /* couldn't rewind to beginning */ + return CURL_SEEKFUNC_FAIL; + + while(left) { + long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left; + if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR)) + /* couldn't seek forwards the desired amount */ + return CURL_SEEKFUNC_FAIL; + left -= step; + } + return CURL_SEEKFUNC_OK; + } +#endif + + if(LSEEK_ERROR == lseek(in->fd, offset, whence)) + /* couldn't rewind, the reason is in errno but errno is just not portable + enough and we don't actually care that much why we failed. We'll let + libcurl know that it may try other means if it wants to. */ + return CURL_SEEKFUNC_CANTSEEK; + + return CURL_SEEKFUNC_OK; +} + +#ifdef USE_TOOL_FTRUNCATE + +#ifdef __BORLANDC__ +/* 64-bit lseek-like function unavailable */ +# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) +#endif + +#ifdef __POCC__ +# if(__POCC__ < 450) +/* 64-bit lseek-like function unavailable */ +# define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence) +# else +# undef _lseeki64 +# define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence) +# endif +#endif + +#ifdef _WIN32_WCE +/* 64-bit lseek-like function unavailable */ +# undef _lseeki64 +# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) +# undef _get_osfhandle +# define _get_osfhandle(fd) (fd) +#endif + +/* + * Truncate a file handle at a 64-bit position 'where'. + */ + +int tool_ftruncate64(int fd, curl_off_t where) +{ + intptr_t handle = _get_osfhandle(fd); + + if(_lseeki64(fd, where, SEEK_SET) < 0) + return -1; + + if(!SetEndOfFile((HANDLE)handle)) + return -1; + + return 0; +} + +#endif /* USE_TOOL_FTRUNCATE */ diff --git a/contrib/libs/curl/src/tool_cb_see.h b/contrib/libs/curl/src/tool_cb_see.h new file mode 100644 index 0000000000..4af0b0ab40 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_see.h @@ -0,0 +1,46 @@ +#ifndef HEADER_CURL_TOOL_CB_SEE_H +#define HEADER_CURL_TOOL_CB_SEE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(WIN32) && !defined(HAVE_FTRUNCATE) + +int tool_ftruncate64(int fd, curl_off_t where); + +#undef ftruncate +#define ftruncate(fd,where) tool_ftruncate64(fd,where) + +#define HAVE_FTRUNCATE 1 +#define USE_TOOL_FTRUNCATE 1 + +#endif /* WIN32 && ! HAVE_FTRUNCATE */ + +/* +** callback for CURLOPT_SEEKFUNCTION +*/ + +int tool_seek_cb(void *userdata, curl_off_t offset, int whence); + +#endif /* HEADER_CURL_TOOL_CB_SEE_H */ diff --git a/contrib/libs/curl/src/tool_cb_wrt.c b/contrib/libs/curl/src/tool_cb_wrt.c new file mode 100644 index 0000000000..c9d1dbd1d2 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_wrt.c @@ -0,0 +1,296 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_FCNTL_H +/* for open() */ +#include <fcntl.h> +#endif + +#include <sys/stat.h> + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_cb_wrt.h" +#include "tool_operate.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifdef WIN32 +#define OPENMODE S_IREAD | S_IWRITE +#else +#define OPENMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH +#endif + +/* create/open a local file for writing, return TRUE on success */ +bool tool_create_output_file(struct OutStruct *outs, + struct OperationConfig *config) +{ + struct GlobalConfig *global; + FILE *file = NULL; + char *fname = outs->filename; + char *aname = NULL; + DEBUGASSERT(outs); + DEBUGASSERT(config); + global = config->global; + if(!fname || !*fname) { + warnf(global, "Remote filename has no length!\n"); + return FALSE; + } + + if(config->output_dir && outs->is_cd_filename) { + aname = aprintf("%s/%s", config->output_dir, fname); + if(!aname) { + errorf(global, "out of memory\n"); + return FALSE; + } + fname = aname; + } + + if(config->file_clobber_mode == CLOBBER_ALWAYS || + (config->file_clobber_mode == CLOBBER_DEFAULT && + !outs->is_cd_filename)) { + /* open file for writing */ + file = fopen(fname, "wb"); + } + else { + int fd; + do { + fd = open(fname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE); + /* Keep retrying in the hope that it isn't interrupted sometime */ + } while(fd == -1 && errno == EINTR); + if(config->file_clobber_mode == CLOBBER_NEVER && fd == -1) { + int next_num = 1; + size_t len = strlen(fname); + size_t newlen = len + 13; /* nul + 1-11 digits + dot */ + char *newname; + /* Guard against wraparound in new filename */ + if(newlen < len) { + free(aname); + errorf(global, "overflow in filename generation\n"); + return FALSE; + } + newname = malloc(newlen); + if(!newname) { + errorf(global, "out of memory\n"); + free(aname); + return FALSE; + } + memcpy(newname, fname, len); + newname[len] = '.'; + while(fd == -1 && /* haven't successfully opened a file */ + (errno == EEXIST || errno == EISDIR) && + /* because we keep having files that already exist */ + next_num < 100 /* and we haven't reached the retry limit */ ) { + curlx_msnprintf(newname + len + 1, 12, "%d", next_num); + next_num++; + do { + fd = open(newname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE); + /* Keep retrying in the hope that it isn't interrupted sometime */ + } while(fd == -1 && errno == EINTR); + } + outs->filename = newname; /* remember the new one */ + outs->alloc_filename = TRUE; + } + /* An else statement to not overwrite existing files and not retry with + new numbered names (which would cover + config->file_clobber_mode == CLOBBER_DEFAULT && outs->is_cd_filename) + is not needed because we would have failed earlier, in the while loop + and `fd` would now be -1 */ + if(fd != -1) { + file = fdopen(fd, "wb"); + if(!file) + close(fd); + } + } + + if(!file) { + warnf(global, "Failed to open the file %s: %s\n", fname, + strerror(errno)); + free(aname); + return FALSE; + } + free(aname); + outs->s_isreg = TRUE; + outs->fopened = TRUE; + outs->stream = file; + outs->bytes = 0; + outs->init = 0; + return TRUE; +} + +/* +** callback for CURLOPT_WRITEFUNCTION +*/ + +size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) +{ + size_t rc; + struct per_transfer *per = userdata; + struct OutStruct *outs = &per->outs; + struct OperationConfig *config = per->config; + size_t bytes = sz * nmemb; + bool is_tty = config->global->isatty; +#ifdef WIN32 + CONSOLE_SCREEN_BUFFER_INFO console_info; + intptr_t fhnd; +#endif + + /* + * Once that libcurl has called back tool_write_cb() the returned value + * is checked against the amount that was intended to be written, if + * it does not match then it fails with CURLE_WRITE_ERROR. So at this + * point returning a value different from sz*nmemb indicates failure. + */ + const size_t failure = bytes ? 0 : 1; + +#ifdef DEBUGBUILD + { + char *tty = curlx_getenv("CURL_ISATTY"); + if(tty) { + is_tty = TRUE; + curl_free(tty); + } + } + + if(config->show_headers) { + if(bytes > (size_t)CURL_MAX_HTTP_HEADER) { + warnf(config->global, "Header data size exceeds single call write " + "limit!\n"); + return failure; + } + } + else { + if(bytes > (size_t)CURL_MAX_WRITE_SIZE) { + warnf(config->global, "Data size exceeds single call write limit!\n"); + return failure; + } + } + + { + /* Some internal congruency checks on received OutStruct */ + bool check_fails = FALSE; + if(outs->filename) { + /* regular file */ + if(!*outs->filename) + check_fails = TRUE; + if(!outs->s_isreg) + check_fails = TRUE; + if(outs->fopened && !outs->stream) + check_fails = TRUE; + if(!outs->fopened && outs->stream) + check_fails = TRUE; + if(!outs->fopened && outs->bytes) + check_fails = TRUE; + } + else { + /* standard stream */ + if(!outs->stream || outs->s_isreg || outs->fopened) + check_fails = TRUE; + if(outs->alloc_filename || outs->is_cd_filename || outs->init) + check_fails = TRUE; + } + if(check_fails) { + warnf(config->global, "Invalid output struct data for write callback\n"); + return failure; + } + } +#endif + + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return failure; + + if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) { + /* binary output to terminal? */ + if(memchr(buffer, 0, bytes)) { + warnf(config->global, "Binary output can mess up your terminal. " + "Use \"--output -\" to tell curl to output it to your terminal " + "anyway, or consider \"--output <FILE>\" to save to a file.\n"); + config->synthetic_error = TRUE; + return failure; + } + } + +#ifdef WIN32 + fhnd = _get_osfhandle(fileno(outs->stream)); + if(isatty(fileno(outs->stream)) && + GetConsoleScreenBufferInfo((HANDLE)fhnd, &console_info)) { + DWORD in_len = (DWORD)(sz * nmemb); + wchar_t* wc_buf; + DWORD wc_len; + + /* calculate buffer size for wide characters */ + wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, NULL, 0); + wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t)); + if(!wc_buf) + return failure; + + /* calculate buffer size for multi-byte characters */ + wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, wc_buf, wc_len); + if(!wc_len) { + free(wc_buf); + return failure; + } + + if(!WriteConsoleW( + (HANDLE) fhnd, + wc_buf, + wc_len, + &wc_len, + NULL)) { + free(wc_buf); + return failure; + } + free(wc_buf); + rc = bytes; + } + else +#endif + rc = fwrite(buffer, sz, nmemb, outs->stream); + + if(bytes == rc) + /* we added this amount of data to the output */ + outs->bytes += bytes; + + if(config->readbusy) { + config->readbusy = FALSE; + curl_easy_pause(per->curl, CURLPAUSE_CONT); + } + + if(config->nobuffer) { + /* output buffering disabled */ + int res = fflush(outs->stream); + if(res) + return failure; + } + + return rc; +} diff --git a/contrib/libs/curl/src/tool_cb_wrt.h b/contrib/libs/curl/src/tool_cb_wrt.h new file mode 100644 index 0000000000..0cbbceefe6 --- /dev/null +++ b/contrib/libs/curl/src/tool_cb_wrt.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_TOOL_CB_WRT_H +#define HEADER_CURL_TOOL_CB_WRT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* +** callback for CURLOPT_WRITEFUNCTION +*/ + +size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata); + +/* create a local file for writing, return TRUE on success */ +bool tool_create_output_file(struct OutStruct *outs, + struct OperationConfig *config); + +#endif /* HEADER_CURL_TOOL_CB_WRT_H */ diff --git a/contrib/libs/curl/src/tool_cfgable.c b/contrib/libs/curl/src/tool_cfgable.c new file mode 100644 index 0000000000..eccb3bcb59 --- /dev/null +++ b/contrib/libs/curl/src/tool_cfgable.c @@ -0,0 +1,188 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "tool_cfgable.h" +#include "tool_main.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void config_init(struct OperationConfig *config) +{ + memset(config, 0, sizeof(struct OperationConfig)); + + config->postfieldsize = -1; + config->use_httpget = FALSE; + config->create_dirs = FALSE; + config->maxredirs = DEFAULT_MAXREDIRS; + config->proto_present = FALSE; + config->proto_redir_present = FALSE; + config->proto_default = NULL; + config->tcp_nodelay = TRUE; /* enabled by default */ + config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT; + config->http09_allowed = FALSE; + config->ftp_skip_ip = TRUE; + config->file_clobber_mode = CLOBBER_DEFAULT; +} + +static void free_config_fields(struct OperationConfig *config) +{ + struct getout *urlnode; + + Curl_safefree(config->useragent); + Curl_safefree(config->altsvc); + Curl_safefree(config->hsts); + curl_slist_free_all(config->cookies); + Curl_safefree(config->cookiejar); + curl_slist_free_all(config->cookiefiles); + + Curl_safefree(config->postfields); + Curl_safefree(config->referer); + + Curl_safefree(config->headerfile); + Curl_safefree(config->ftpport); + Curl_safefree(config->iface); + + Curl_safefree(config->range); + + Curl_safefree(config->userpwd); + Curl_safefree(config->tls_username); + Curl_safefree(config->tls_password); + Curl_safefree(config->tls_authtype); + Curl_safefree(config->proxy_tls_username); + Curl_safefree(config->proxy_tls_password); + Curl_safefree(config->proxy_tls_authtype); + Curl_safefree(config->proxyuserpwd); + Curl_safefree(config->proxy); + + Curl_safefree(config->dns_ipv6_addr); + Curl_safefree(config->dns_ipv4_addr); + Curl_safefree(config->dns_interface); + Curl_safefree(config->dns_servers); + + Curl_safefree(config->noproxy); + + Curl_safefree(config->mail_from); + curl_slist_free_all(config->mail_rcpt); + Curl_safefree(config->mail_auth); + + Curl_safefree(config->netrc_file); + Curl_safefree(config->output_dir); + + urlnode = config->url_list; + while(urlnode) { + struct getout *next = urlnode->next; + Curl_safefree(urlnode->url); + Curl_safefree(urlnode->outfile); + Curl_safefree(urlnode->infile); + Curl_safefree(urlnode); + urlnode = next; + } + config->url_list = NULL; + config->url_last = NULL; + config->url_get = NULL; + config->url_out = NULL; + + Curl_safefree(config->doh_url); + Curl_safefree(config->cipher_list); + Curl_safefree(config->proxy_cipher_list); + Curl_safefree(config->cert); + Curl_safefree(config->proxy_cert); + Curl_safefree(config->cert_type); + Curl_safefree(config->proxy_cert_type); + Curl_safefree(config->cacert); + Curl_safefree(config->login_options); + Curl_safefree(config->proxy_cacert); + Curl_safefree(config->capath); + Curl_safefree(config->proxy_capath); + Curl_safefree(config->crlfile); + Curl_safefree(config->pinnedpubkey); + Curl_safefree(config->proxy_pinnedpubkey); + Curl_safefree(config->proxy_crlfile); + Curl_safefree(config->key); + Curl_safefree(config->proxy_key); + Curl_safefree(config->key_type); + Curl_safefree(config->proxy_key_type); + Curl_safefree(config->key_passwd); + Curl_safefree(config->proxy_key_passwd); + Curl_safefree(config->pubkey); + Curl_safefree(config->hostpubmd5); + Curl_safefree(config->hostpubsha256); + Curl_safefree(config->engine); + Curl_safefree(config->etag_save_file); + Curl_safefree(config->etag_compare_file); + Curl_safefree(config->request_target); + Curl_safefree(config->customrequest); + Curl_safefree(config->krblevel); + + Curl_safefree(config->oauth_bearer); + Curl_safefree(config->sasl_authzid); + + Curl_safefree(config->unix_socket_path); + Curl_safefree(config->writeout); + Curl_safefree(config->proto_default); + + curl_slist_free_all(config->quote); + curl_slist_free_all(config->postquote); + curl_slist_free_all(config->prequote); + + curl_slist_free_all(config->headers); + curl_slist_free_all(config->proxyheaders); + + curl_mime_free(config->mimepost); + config->mimepost = NULL; + tool_mime_free(config->mimeroot); + config->mimeroot = NULL; + config->mimecurrent = NULL; + + curl_slist_free_all(config->telnet_options); + curl_slist_free_all(config->resolve); + curl_slist_free_all(config->connect_to); + + Curl_safefree(config->preproxy); + Curl_safefree(config->proxy_service_name); + Curl_safefree(config->service_name); + + Curl_safefree(config->ftp_account); + Curl_safefree(config->ftp_alternative_to_user); + + Curl_safefree(config->aws_sigv4); + Curl_safefree(config->proto_str); + Curl_safefree(config->proto_redir_str); +} + +void config_free(struct OperationConfig *config) +{ + struct OperationConfig *last = config; + + /* Free each of the structures in reverse order */ + while(last) { + struct OperationConfig *prev = last->prev; + + free_config_fields(last); + free(last); + + last = prev; + } +} diff --git a/contrib/libs/curl/src/tool_cfgable.h b/contrib/libs/curl/src/tool_cfgable.h new file mode 100644 index 0000000000..ec26eebf60 --- /dev/null +++ b/contrib/libs/curl/src/tool_cfgable.h @@ -0,0 +1,338 @@ +#ifndef HEADER_CURL_TOOL_CFGABLE_H +#define HEADER_CURL_TOOL_CFGABLE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#include "tool_sdecls.h" +#include "tool_urlglob.h" +#include "tool_formparse.h" + +struct GlobalConfig; + +struct State { + struct getout *urlnode; + struct URLGlob *inglob; + struct URLGlob *urls; + char *outfiles; + char *httpgetfields; + char *uploadfile; + unsigned long infilenum; /* number of files to upload */ + unsigned long up; /* upload file counter within a single upload glob */ + unsigned long urlnum; /* how many iterations this single URL has with ranges + etc */ + unsigned long li; +}; + +struct OperationConfig { + bool remote_time; + char *useragent; + struct curl_slist *cookies; /* cookies to serialize into a single line */ + char *cookiejar; /* write to this file */ + struct curl_slist *cookiefiles; /* file(s) to load cookies from */ + char *altsvc; /* alt-svc cache file name */ + char *hsts; /* HSTS cache file name */ + bool cookiesession; /* new session? */ + bool encoding; /* Accept-Encoding please */ + bool tr_encoding; /* Transfer-Encoding please */ + unsigned long authtype; /* auth bitmask */ + bool use_resume; + bool resume_from_current; + bool disable_epsv; + bool disable_eprt; + bool ftp_pret; + char *proto_str; + bool proto_present; + char *proto_redir_str; + bool proto_redir_present; + char *proto_default; + curl_off_t resume_from; + char *postfields; + curl_off_t postfieldsize; + char *referer; + double timeout; + double connecttimeout; + long maxredirs; + curl_off_t max_filesize; + char *output_dir; + char *headerfile; + char *ftpport; + char *iface; + long localport; + long localportrange; + unsigned short porttouse; + char *range; + long low_speed_limit; + long low_speed_time; + char *dns_servers; /* dot notation: 1.1.1.1;2.2.2.2 */ + char *dns_interface; /* interface name */ + char *dns_ipv4_addr; /* dot notation */ + char *dns_ipv6_addr; /* dot notation */ + char *userpwd; + char *login_options; + char *tls_username; + char *tls_password; + char *tls_authtype; + char *proxy_tls_username; + char *proxy_tls_password; + char *proxy_tls_authtype; + char *proxyuserpwd; + char *proxy; + int proxyver; /* set to CURLPROXY_HTTP* define */ + char *noproxy; + char *mail_from; + struct curl_slist *mail_rcpt; + char *mail_auth; + bool mail_rcpt_allowfails; /* --mail-rcpt-allowfails */ + char *sasl_authzid; /* Authorization identity (identity to use) */ + bool sasl_ir; /* Enable/disable SASL initial response */ + bool proxytunnel; + bool ftp_append; /* APPE on ftp */ + bool use_ascii; /* select ascii or text transfer */ + bool autoreferer; /* automatically set referer */ + bool failonerror; /* fail on (HTTP) errors */ + bool failwithbody; /* fail on (HTTP) errors but still store body */ + bool show_headers; /* show headers to data output */ + bool no_body; /* don't get the body */ + bool dirlistonly; /* only get the FTP dir list */ + bool followlocation; /* follow http redirects */ + bool unrestricted_auth; /* Continue to send authentication (user+password) + when following ocations, even when hostname + changed */ + bool netrc_opt; + bool netrc; + char *netrc_file; + struct getout *url_list; /* point to the first node */ + struct getout *url_last; /* point to the last/current node */ + struct getout *url_get; /* point to the node to fill in URL */ + struct getout *url_out; /* point to the node to fill in outfile */ + struct getout *url_ul; /* point to the node to fill in upload */ + char *doh_url; + char *cipher_list; + char *proxy_cipher_list; + char *cipher13_list; + char *proxy_cipher13_list; + char *cert; + char *proxy_cert; + char *cert_type; + char *proxy_cert_type; + char *cacert; + char *proxy_cacert; + char *capath; + char *proxy_capath; + char *crlfile; + char *proxy_crlfile; + char *pinnedpubkey; + char *proxy_pinnedpubkey; + char *key; + char *proxy_key; + char *key_type; + char *proxy_key_type; + char *key_passwd; + char *proxy_key_passwd; + char *pubkey; + char *hostpubmd5; + char *hostpubsha256; + char *engine; + char *etag_save_file; + char *etag_compare_file; + bool crlf; + char *customrequest; + char *ssl_ec_curves; + char *krblevel; + char *request_target; + long httpversion; + bool http09_allowed; + bool nobuffer; + bool readbusy; /* set when reading input returns EAGAIN */ + bool globoff; + bool use_httpget; + bool insecure_ok; /* set TRUE to allow insecure SSL connects */ + bool doh_insecure_ok; /* set TRUE to allow insecure SSL connects + for DoH */ + bool proxy_insecure_ok; /* set TRUE to allow insecure SSL connects + for proxy */ + bool terminal_binary_ok; + bool verifystatus; + bool doh_verifystatus; + bool create_dirs; + bool ftp_create_dirs; + bool ftp_skip_ip; + bool proxynegotiate; + bool proxyntlm; + bool proxydigest; + bool proxybasic; + bool proxyanyauth; + bool jsoned; /* added json content-type */ + char *writeout; /* %-styled format string to output */ + struct curl_slist *quote; + struct curl_slist *postquote; + struct curl_slist *prequote; + long ssl_version; + long ssl_version_max; + long proxy_ssl_version; + long ip_version; + long create_file_mode; /* CURLOPT_NEW_FILE_PERMS */ + curl_TimeCond timecond; + curl_off_t condtime; + struct curl_slist *headers; + struct curl_slist *proxyheaders; + struct tool_mime *mimeroot; + struct tool_mime *mimecurrent; + curl_mime *mimepost; + struct curl_slist *telnet_options; + struct curl_slist *resolve; + struct curl_slist *connect_to; + HttpReq httpreq; + + /* for bandwidth limiting features: */ + curl_off_t sendpersecond; /* send to peer */ + curl_off_t recvpersecond; /* receive from peer */ + + bool ftp_ssl; + bool ftp_ssl_reqd; + bool ftp_ssl_control; + bool ftp_ssl_ccc; + int ftp_ssl_ccc_mode; + char *preproxy; + int socks5_gssapi_nec; /* The NEC reference server does not protect the + encryption type exchange */ + unsigned long socks5_auth;/* auth bitmask for socks5 proxies */ + char *proxy_service_name; /* set authentication service name for HTTP and + SOCKS5 proxies */ + char *service_name; /* set authentication service name for DIGEST-MD5, + Kerberos 5 and SPNEGO */ + + bool tcp_nodelay; + bool tcp_fastopen; + long req_retry; /* number of retries */ + bool retry_all_errors; /* retry on any error */ + bool retry_connrefused; /* set connection refused as a transient error */ + long retry_delay; /* delay between retries (in seconds) */ + long retry_maxtime; /* maximum time to keep retrying */ + + char *ftp_account; /* for ACCT */ + char *ftp_alternative_to_user; /* send command if USER/PASS fails */ + int ftp_filemethod; + long mime_options; /* Mime option flags. */ + long tftp_blksize; /* TFTP BLKSIZE option */ + bool tftp_no_options; /* do not send TFTP options requests */ + bool ignorecl; /* --ignore-content-length */ + bool disable_sessionid; + + bool raw; + bool post301; + bool post302; + bool post303; + bool nokeepalive; /* for keepalive needs */ + long alivetime; + bool content_disposition; /* use Content-disposition filename */ + + int default_node_flags; /* default flags to search for each 'node', which + is basically each given URL to transfer */ + + bool xattr; /* store metadata in extended attributes */ + long gssapi_delegation; + bool ssl_allow_beast; /* allow this SSL vulnerability */ + bool proxy_ssl_allow_beast; /* allow this SSL vulnerability for proxy*/ + + bool ssl_no_revoke; /* disable SSL certificate revocation checks */ + /*bool proxy_ssl_no_revoke; */ + + bool ssl_revoke_best_effort; /* ignore SSL revocation offline/missing + revocation list errors */ + + bool native_ca_store; /* use the native os ca store */ + bool ssl_auto_client_cert; /* automatically locate and use a client + certificate for authentication (Schannel) */ + bool proxy_ssl_auto_client_cert; /* proxy version of ssl_auto_client_cert */ + char *oauth_bearer; /* OAuth 2.0 bearer token */ + bool nonpn; /* enable/disable TLS NPN extension */ + bool noalpn; /* enable/disable TLS ALPN extension */ + char *unix_socket_path; /* path to Unix domain socket */ + bool abstract_unix_socket; /* path to an abstract Unix domain socket */ + bool falsestart; + bool path_as_is; + double expect100timeout; + bool suppress_connect_headers; /* suppress proxy CONNECT response headers + from user callbacks */ + bool synthetic_error; /* if TRUE, this is tool-internal error */ + bool ssh_compression; /* enable/disable SSH compression */ + long happy_eyeballs_timeout_ms; /* happy eyeballs timeout in milliseconds. + 0 is valid. default: CURL_HET_DEFAULT. */ + bool haproxy_protocol; /* whether to send HAProxy protocol v1 */ + bool disallow_username_in_url; /* disallow usernames in URLs */ + char *aws_sigv4; + enum { + CLOBBER_DEFAULT, /* Provides compatibility with previous versions of curl, + by using the default behavior for -o, -O, and -J. + If those options would have overwritten files, like + -o and -O would, then overwrite them. In the case of + -J, this will not overwrite any files. */ + CLOBBER_NEVER, /* If the file exists, always fail */ + CLOBBER_ALWAYS /* If the file exists, always overwrite it */ + } file_clobber_mode; + struct GlobalConfig *global; + struct OperationConfig *prev; + struct OperationConfig *next; /* Always last in the struct */ + struct State state; /* for create_transfer() */ + bool rm_partial; /* on error, remove partially written output + files */ +}; + +struct GlobalConfig { + int showerror; /* -1 == unset, default => show errors + 0 => -s is used to NOT show errors + 1 => -S has been used to show errors */ + bool mute; /* don't show messages, --silent given */ + bool noprogress; /* don't show progress bar --silent given */ + bool isatty; /* Updated internally if output is a tty */ + FILE *errors; /* Error stream, defaults to stderr */ + bool errors_fopened; /* Whether error stream isn't stderr */ + char *trace_dump; /* file to dump the network trace to */ + FILE *trace_stream; + bool trace_fopened; + trace tracetype; + bool tracetime; /* include timestamp? */ + int progressmode; /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */ + char *libcurl; /* Output libcurl code to this file name */ + bool fail_early; /* exit on first transfer error */ + bool styled_output; /* enable fancy output style detection */ + long ms_per_transfer; /* start next transfer after (at least) this + many milliseconds */ +#ifdef CURLDEBUG + bool test_event_based; +#endif + bool parallel; + long parallel_max; + bool parallel_connect; + char *help_category; /* The help category, if set */ + struct OperationConfig *first; + struct OperationConfig *current; + struct OperationConfig *last; /* Always last in the struct */ +}; + +void config_init(struct OperationConfig *config); +void config_free(struct OperationConfig *config); + +#endif /* HEADER_CURL_TOOL_CFGABLE_H */ diff --git a/contrib/libs/curl/src/tool_dirhie.c b/contrib/libs/curl/src/tool_dirhie.c new file mode 100644 index 0000000000..1b6ac17480 --- /dev/null +++ b/contrib/libs/curl/src/tool_dirhie.c @@ -0,0 +1,172 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include <sys/stat.h> + +#ifdef WIN32 +# include <direct.h> +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_dirhie.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef NETWARE +# ifndef __NOVELL_LIBC__ +# define mkdir mkdir_510 +# endif +#endif + +#if defined(WIN32) || (defined(MSDOS) && !defined(__DJGPP__)) +# define mkdir(x,y) (mkdir)((x)) +# ifndef F_OK +# define F_OK 0 +# endif +#endif + +static void show_dir_errno(FILE *errors, const char *name) +{ + switch(errno) { +#ifdef EACCES + case EACCES: + fprintf(errors, "You don't have permission to create %s.\n", name); + break; +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: + fprintf(errors, "The directory name %s is too long.\n", name); + break; +#endif +#ifdef EROFS + case EROFS: + fprintf(errors, "%s resides on a read-only file system.\n", name); + break; +#endif +#ifdef ENOSPC + case ENOSPC: + fprintf(errors, "No space left on the file system that will " + "contain the directory %s.\n", name); + break; +#endif +#ifdef EDQUOT + case EDQUOT: + fprintf(errors, "Cannot create directory %s because you " + "exceeded your quota.\n", name); + break; +#endif + default : + fprintf(errors, "Error creating directory %s.\n", name); + break; + } +} + +/* + * Create the needed directory hierarchy recursively in order to save + * multi-GETs in file output, ie: + * curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt" + * should create all the dir* automagically + */ + +#if defined(WIN32) || defined(__DJGPP__) +/* systems that may use either or when specifying a path */ +#define PATH_DELIMITERS "\\/" +#else +#define PATH_DELIMITERS DIR_CHAR +#endif + + +CURLcode create_dir_hierarchy(const char *outfile, FILE *errors) +{ + char *tempdir; + char *tempdir2; + char *outdup; + char *dirbuildup; + CURLcode result = CURLE_OK; + size_t outlen; + + outlen = strlen(outfile); + outdup = strdup(outfile); + if(!outdup) + return CURLE_OUT_OF_MEMORY; + + dirbuildup = malloc(outlen + 1); + if(!dirbuildup) { + Curl_safefree(outdup); + return CURLE_OUT_OF_MEMORY; + } + dirbuildup[0] = '\0'; + + /* Allow strtok() here since this isn't used threaded */ + /* !checksrc! disable BANNEDFUNC 2 */ + tempdir = strtok(outdup, PATH_DELIMITERS); + + while(tempdir) { + bool skip = false; + tempdir2 = strtok(NULL, PATH_DELIMITERS); + /* since strtok returns a token for the last word even + if not ending with DIR_CHAR, we need to prune it */ + if(tempdir2) { + size_t dlen = strlen(dirbuildup); + if(dlen) + msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir); + else { + if(outdup == tempdir) { +#if defined(MSDOS) || defined(WIN32) + /* Skip creating a drive's current directory. + It may seem as though that would harmlessly fail but it could be + a corner case if X: did not exist, since we would be creating it + erroneously. + eg if outfile is X:\foo\bar\filename then don't mkdir X: + This logic takes into account unsupported drives !:, 1:, etc. */ + char *p = strchr(tempdir, ':'); + if(p && !p[1]) + skip = true; +#endif + /* the output string doesn't start with a separator */ + strcpy(dirbuildup, tempdir); + } + else + msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir); + } + /* Create directory. Ignore access denied error to allow traversal. */ + if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) && + (errno != EACCES) && (errno != EEXIST)) { + show_dir_errno(errors, dirbuildup); + result = CURLE_WRITE_ERROR; + break; /* get out of loop */ + } + } + tempdir = tempdir2; + } + + Curl_safefree(dirbuildup); + Curl_safefree(outdup); + + return result; +} diff --git a/contrib/libs/curl/src/tool_dirhie.h b/contrib/libs/curl/src/tool_dirhie.h new file mode 100644 index 0000000000..954f3e2488 --- /dev/null +++ b/contrib/libs/curl/src/tool_dirhie.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_TOOL_DIRHIE_H +#define HEADER_CURL_TOOL_DIRHIE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +CURLcode create_dir_hierarchy(const char *outfile, FILE *errors); + +#endif /* HEADER_CURL_TOOL_DIRHIE_H */ diff --git a/contrib/libs/curl/src/tool_doswin.c b/contrib/libs/curl/src/tool_doswin.c new file mode 100644 index 0000000000..d8695e93c2 --- /dev/null +++ b/contrib/libs/curl/src/tool_doswin.c @@ -0,0 +1,787 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(MSDOS) || defined(WIN32) + +#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) +# include <libgen.h> +#endif + +#ifdef WIN32 +# include <stdlib.h> +# include <tlhelp32.h> +# include "tool_cfgable.h" +# include "tool_libinfo.h" +#endif + +#include "tool_bname.h" +#include "tool_doswin.h" + +#include "curlx.h" +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef WIN32 +# undef PATH_MAX +# define PATH_MAX MAX_PATH +#endif + +#ifndef S_ISCHR +# ifdef S_IFCHR +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# else +# define S_ISCHR(m) (0) /* cannot tell if file is a device */ +# endif +#endif + +#ifdef WIN32 +# define _use_lfn(f) (1) /* long file names always available */ +#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */ +# define _use_lfn(f) (0) /* long file names never available */ +#elif defined(__DJGPP__) +# include <fcntl.h> /* _use_lfn(f) prototype */ +#endif + +#ifndef UNITTESTS +static SANITIZEcode truncate_dryrun(const char *path, + const size_t truncate_pos); +#ifdef MSDOS +static SANITIZEcode msdosify(char **const sanitized, const char *file_name, + int flags); +#endif +static SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, + const char *file_name, + int flags); +#endif /* !UNITTESTS (static declarations used if no unit tests) */ + + +/* +Sanitize a file or path name. + +All banned characters are replaced by underscores, for example: +f?*foo => f__foo +f:foo::$DATA => f_foo__$DATA +f:\foo:bar => f__foo_bar +f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH) + +This function was implemented according to the guidelines in 'Naming Files, +Paths, and Namespaces' section 'Naming Conventions'. +https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx + +Flags +----- +SANITIZE_ALLOW_COLONS: Allow colons. +Without this flag colons are sanitized. + +SANITIZE_ALLOW_PATH: Allow path separators and colons. +Without this flag path separators and colons are sanitized. + +SANITIZE_ALLOW_RESERVED: Allow reserved device names. +Without this flag a reserved device name is renamed (COM1 => _COM1) unless it's +in a UNC prefixed path. + +SANITIZE_ALLOW_TRUNCATE: Allow truncating a long filename. +Without this flag if the sanitized filename or path will be too long an error +occurs. With this flag the filename --and not any other parts of the path-- may +be truncated to at least a single character. A filename followed by an +alternate data stream (ADS) cannot be truncated in any case. + +Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. +Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. +*/ +SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name, + int flags) +{ + char *p, *target; + size_t len; + SANITIZEcode sc; + size_t max_sanitized_len; + + if(!sanitized) + return SANITIZE_ERR_BAD_ARGUMENT; + + *sanitized = NULL; + + if(!file_name) + return SANITIZE_ERR_BAD_ARGUMENT; + + if((flags & SANITIZE_ALLOW_PATH)) { +#ifndef MSDOS + if(file_name[0] == '\\' && file_name[1] == '\\') + /* UNC prefixed path \\ (eg \\?\C:\foo) */ + max_sanitized_len = 32767-1; + else +#endif + max_sanitized_len = PATH_MAX-1; + } + else + /* The maximum length of a filename. + FILENAME_MAX is often the same as PATH_MAX, in other words it is 260 and + does not discount the path information therefore we shouldn't use it. */ + max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1; + + len = strlen(file_name); + if(len > max_sanitized_len) { + if(!(flags & SANITIZE_ALLOW_TRUNCATE) || + truncate_dryrun(file_name, max_sanitized_len)) + return SANITIZE_ERR_INVALID_PATH; + + len = max_sanitized_len; + } + + target = malloc(len + 1); + if(!target) + return SANITIZE_ERR_OUT_OF_MEMORY; + + strncpy(target, file_name, len); + target[len] = '\0'; + +#ifndef MSDOS + if((flags & SANITIZE_ALLOW_PATH) && !strncmp(target, "\\\\?\\", 4)) + /* Skip the literal path prefix \\?\ */ + p = target + 4; + else +#endif + p = target; + + /* replace control characters and other banned characters */ + for(; *p; ++p) { + const char *banned; + + if((1 <= *p && *p <= 31) || + (!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *p == ':') || + (!(flags & SANITIZE_ALLOW_PATH) && (*p == '/' || *p == '\\'))) { + *p = '_'; + continue; + } + + for(banned = "|<>\"?*"; *banned; ++banned) { + if(*p == *banned) { + *p = '_'; + break; + } + } + } + + /* remove trailing spaces and periods if not allowing paths */ + if(!(flags & SANITIZE_ALLOW_PATH) && len) { + char *clip = NULL; + + p = &target[len]; + do { + --p; + if(*p != ' ' && *p != '.') + break; + clip = p; + } while(p != target); + + if(clip) { + *clip = '\0'; + len = clip - target; + } + } + +#ifdef MSDOS + sc = msdosify(&p, target, flags); + free(target); + if(sc) + return sc; + target = p; + len = strlen(target); + + if(len > max_sanitized_len) { + free(target); + return SANITIZE_ERR_INVALID_PATH; + } +#endif + + if(!(flags & SANITIZE_ALLOW_RESERVED)) { + sc = rename_if_reserved_dos_device_name(&p, target, flags); + free(target); + if(sc) + return sc; + target = p; + len = strlen(target); + + if(len > max_sanitized_len) { + free(target); + return SANITIZE_ERR_INVALID_PATH; + } + } + + *sanitized = target; + return SANITIZE_ERR_OK; +} + + +/* +Test if truncating a path to a file will leave at least a single character in +the filename. Filenames suffixed by an alternate data stream can't be +truncated. This performs a dry run, nothing is modified. + +Good truncate_pos 9: C:\foo\bar => C:\foo\ba +Good truncate_pos 6: C:\foo => C:\foo +Good truncate_pos 5: C:\foo => C:\fo +Bad* truncate_pos 5: C:foo => C:foo +Bad truncate_pos 5: C:\foo:ads => C:\fo +Bad truncate_pos 9: C:\foo:ads => C:\foo:ad +Bad truncate_pos 5: C:\foo\bar => C:\fo +Bad truncate_pos 5: C:\foo\ => C:\fo +Bad truncate_pos 7: C:\foo\ => C:\foo\ +Error truncate_pos 7: C:\foo => (pos out of range) +Bad truncate_pos 1: C:\foo\ => C + +* C:foo is ambiguous, C could end up being a drive or file therefore something + like C:superlongfilename can't be truncated. + +Returns +SANITIZE_ERR_OK: Good -- 'path' can be truncated +SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated +!= SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error +*/ +SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos) +{ + size_t len; + + if(!path) + return SANITIZE_ERR_BAD_ARGUMENT; + + len = strlen(path); + + if(truncate_pos > len) + return SANITIZE_ERR_BAD_ARGUMENT; + + if(!len || !truncate_pos) + return SANITIZE_ERR_INVALID_PATH; + + if(strpbrk(&path[truncate_pos - 1], "\\/:")) + return SANITIZE_ERR_INVALID_PATH; + + /* C:\foo can be truncated but C:\foo:ads can't */ + if(truncate_pos > 1) { + const char *p = &path[truncate_pos - 1]; + do { + --p; + if(*p == ':') + return SANITIZE_ERR_INVALID_PATH; + } while(p != path && *p != '\\' && *p != '/'); + } + + return SANITIZE_ERR_OK; +} + +/* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function + * were taken with modification from the DJGPP port of tar 1.12. They use + * algorithms originally from DJTAR. + */ + +/* +Extra sanitization MSDOS for file_name. + +This is a supporting function for sanitize_file_name. + +Warning: This is an MSDOS legacy function and was purposely written in a way +that some path information may pass through. For example drive letter names +(C:, D:, etc) are allowed to pass through. For sanitizing a filename use +sanitize_file_name. + +Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. +Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. +*/ +#if defined(MSDOS) || defined(UNITTESTS) +SANITIZEcode msdosify(char **const sanitized, const char *file_name, + int flags) +{ + char dos_name[PATH_MAX]; + static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */ + "|<>/\\\":?*"; /* illegal in DOS & W95 */ + static const char *illegal_chars_w95 = &illegal_chars_dos[8]; + int idx, dot_idx; + const char *s = file_name; + char *d = dos_name; + const char *const dlimit = dos_name + sizeof(dos_name) - 1; + const char *illegal_aliens = illegal_chars_dos; + size_t len = sizeof(illegal_chars_dos) - 1; + + if(!sanitized) + return SANITIZE_ERR_BAD_ARGUMENT; + + *sanitized = NULL; + + if(!file_name) + return SANITIZE_ERR_BAD_ARGUMENT; + + if(strlen(file_name) > PATH_MAX-1 && + (!(flags & SANITIZE_ALLOW_TRUNCATE) || + truncate_dryrun(file_name, PATH_MAX-1))) + return SANITIZE_ERR_INVALID_PATH; + + /* Support for Windows 9X VFAT systems, when available. */ + if(_use_lfn(file_name)) { + illegal_aliens = illegal_chars_w95; + len -= (illegal_chars_w95 - illegal_chars_dos); + } + + /* Get past the drive letter, if any. */ + if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') { + *d++ = *s++; + *d = ((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) ? ':' : '_'; + ++d, ++s; + } + + for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) { + if(memchr(illegal_aliens, *s, len)) { + + if((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *s == ':') + *d = ':'; + else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\')) + *d = *s; + /* Dots are special: DOS doesn't allow them as the leading character, + and a file name cannot have more than a single dot. We leave the + first non-leading dot alone, unless it comes too close to the + beginning of the name: we want sh.lex.c to become sh_lex.c, not + sh.lex-c. */ + else if(*s == '.') { + if((flags & SANITIZE_ALLOW_PATH) && idx == 0 && + (s[1] == '/' || s[1] == '\\' || + (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) { + /* Copy "./" and "../" verbatim. */ + *d++ = *s++; + if(d == dlimit) + break; + if(*s == '.') { + *d++ = *s++; + if(d == dlimit) + break; + } + *d = *s; + } + else if(idx == 0) + *d = '_'; + else if(dot_idx >= 0) { + if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */ + d[dot_idx - idx] = '_'; /* replace previous dot */ + *d = '.'; + } + else + *d = '-'; + } + else + *d = '.'; + + if(*s == '.') + dot_idx = idx; + } + else if(*s == '+' && s[1] == '+') { + if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */ + *d++ = 'x'; + if(d == dlimit) + break; + *d = 'x'; + } + else { + /* libg++ etc. */ + if(dlimit - d < 4) { + *d++ = 'x'; + if(d == dlimit) + break; + *d = 'x'; + } + else { + memcpy(d, "plus", 4); + d += 3; + } + } + s++; + idx++; + } + else + *d = '_'; + } + else + *d = *s; + if(*s == '/' || *s == '\\') { + idx = 0; + dot_idx = -1; + } + else + idx++; + } + *d = '\0'; + + if(*s) { + /* dos_name is truncated, check that truncation requirements are met, + specifically truncating a filename suffixed by an alternate data stream + or truncating the entire filename is not allowed. */ + if(!(flags & SANITIZE_ALLOW_TRUNCATE) || strpbrk(s, "\\/:") || + truncate_dryrun(dos_name, d - dos_name)) + return SANITIZE_ERR_INVALID_PATH; + } + + *sanitized = strdup(dos_name); + return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY); +} +#endif /* MSDOS || UNITTESTS */ + +/* +Rename file_name if it's a reserved dos device name. + +This is a supporting function for sanitize_file_name. + +Warning: This is an MSDOS legacy function and was purposely written in a way +that some path information may pass through. For example drive letter names +(C:, D:, etc) are allowed to pass through. For sanitizing a filename use +sanitize_file_name. + +Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name. +Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL. +*/ +SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, + const char *file_name, + int flags) +{ + /* We could have a file whose name is a device on MS-DOS. Trying to + * retrieve such a file would fail at best and wedge us at worst. We need + * to rename such files. */ + char *p, *base; + char fname[PATH_MAX]; +#ifdef MSDOS + struct_stat st_buf; +#endif + + if(!sanitized) + return SANITIZE_ERR_BAD_ARGUMENT; + + *sanitized = NULL; + + if(!file_name) + return SANITIZE_ERR_BAD_ARGUMENT; + + /* Ignore UNC prefixed paths, they are allowed to contain a reserved name. */ +#ifndef MSDOS + if((flags & SANITIZE_ALLOW_PATH) && + file_name[0] == '\\' && file_name[1] == '\\') { + size_t len = strlen(file_name); + *sanitized = malloc(len + 1); + if(!*sanitized) + return SANITIZE_ERR_OUT_OF_MEMORY; + strncpy(*sanitized, file_name, len + 1); + return SANITIZE_ERR_OK; + } +#endif + + if(strlen(file_name) > PATH_MAX-1 && + (!(flags & SANITIZE_ALLOW_TRUNCATE) || + truncate_dryrun(file_name, PATH_MAX-1))) + return SANITIZE_ERR_INVALID_PATH; + + strncpy(fname, file_name, PATH_MAX-1); + fname[PATH_MAX-1] = '\0'; + base = basename(fname); + + /* Rename reserved device names that are known to be accessible without \\.\ + Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS + https://support.microsoft.com/en-us/kb/74496 + https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx + */ + for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) { + size_t p_len; + int x = (curl_strnequal(p, "CON", 3) || + curl_strnequal(p, "PRN", 3) || + curl_strnequal(p, "AUX", 3) || + curl_strnequal(p, "NUL", 3)) ? 3 : + (curl_strnequal(p, "CLOCK$", 6)) ? 6 : + (curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ? + (('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0; + + if(!x) + continue; + + /* the devices may be accessible with an extension or ADS, for + example CON.AIR and 'CON . AIR' and CON:AIR access console */ + + for(; p[x] == ' '; ++x) + ; + + if(p[x] == '.') { + p[x] = '_'; + continue; + } + else if(p[x] == ':') { + if(!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) { + p[x] = '_'; + continue; + } + ++x; + } + else if(p[x]) /* no match */ + continue; + + /* p points to 'CON' or 'CON ' or 'CON:', etc */ + p_len = strlen(p); + + /* Prepend a '_' */ + if(strlen(fname) == PATH_MAX-1) { + --p_len; + if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(p, p_len)) + return SANITIZE_ERR_INVALID_PATH; + p[p_len] = '\0'; + } + memmove(p + 1, p, p_len + 1); + p[0] = '_'; + ++p_len; + + /* if fname was just modified then the basename pointer must be updated */ + if(p == fname) + base = basename(fname); + } + + /* This is the legacy portion from rename_if_dos_device_name that checks for + reserved device names. It only works on MSDOS. On Windows XP the stat + check errors with EINVAL if the device name is reserved. On Windows + Vista/7/8 it sets mode S_IFREG (regular file or device). According to MSDN + stat doc the latter behavior is correct, but that doesn't help us identify + whether it's a reserved device name and not a regular file name. */ +#ifdef MSDOS + if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { + /* Prepend a '_' */ + size_t blen = strlen(base); + if(blen) { + if(strlen(fname) == PATH_MAX-1) { + --blen; + if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(base, blen)) + return SANITIZE_ERR_INVALID_PATH; + base[blen] = '\0'; + } + memmove(base + 1, base, blen + 1); + base[0] = '_'; + } + } +#endif + + *sanitized = strdup(fname); + return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY); +} + +#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) + +/* + * Disable program default argument globbing. We do it on our own. + */ +char **__crt0_glob_function(char *arg) +{ + (void)arg; + return (char **)0; +} + +#endif /* MSDOS && (__DJGPP__ || __GO32__) */ + +#ifdef WIN32 + +/* + * Function to find CACert bundle on a Win32 platform using SearchPath. + * (SearchPath is already declared via inclusions done in setup header file) + * (Use the ASCII version instead of the unicode one!) + * The order of the directories it searches is: + * 1. application's directory + * 2. current working directory + * 3. Windows System directory (e.g. C:\windows\system32) + * 4. Windows Directory (e.g. C:\windows) + * 5. all directories along %PATH% + * + * For WinXP and later search order actually depends on registry value: + * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode + */ + +CURLcode FindWin32CACert(struct OperationConfig *config, + curl_sslbackend backend, + const TCHAR *bundle_file) +{ + CURLcode result = CURLE_OK; + + /* Search and set cert file only if libcurl supports SSL. + * + * If Schannel is the selected SSL backend then these locations are + * ignored. We allow setting CA location for schannel only when explicitly + * specified by the user via CURLOPT_CAINFO / --cacert. + */ + if((curlinfo->features & CURL_VERSION_SSL) && + backend != CURLSSLBACKEND_SCHANNEL) { + + DWORD res_len; + TCHAR buf[PATH_MAX]; + TCHAR *ptr = NULL; + + buf[0] = TEXT('\0'); + + res_len = SearchPath(NULL, bundle_file, NULL, PATH_MAX, buf, &ptr); + if(res_len > 0) { + char *mstr = curlx_convert_tchar_to_UTF8(buf); + Curl_safefree(config->cacert); + if(mstr) + config->cacert = strdup(mstr); + curlx_unicodefree(mstr); + if(!config->cacert) + result = CURLE_OUT_OF_MEMORY; + } + } + + return result; +} + + +/* Get a list of all loaded modules with full paths. + * Returns slist on success or NULL on error. + */ +struct curl_slist *GetLoadedModulePaths(void) +{ + HANDLE hnd = INVALID_HANDLE_VALUE; + MODULEENTRY32 mod = {0}; + struct curl_slist *slist = NULL; + + mod.dwSize = sizeof(MODULEENTRY32); + + do { + hnd = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); + } while(hnd == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH); + + if(hnd == INVALID_HANDLE_VALUE) + goto error; + + if(!Module32First(hnd, &mod)) + goto error; + + do { + char *path; /* points to stack allocated buffer */ + struct curl_slist *temp; + +#ifdef UNICODE + /* sizeof(mod.szExePath) is the max total bytes of wchars. the max total + bytes of multibyte chars won't be more than twice that. */ + char buffer[sizeof(mod.szExePath) * 2]; + if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1, + buffer, sizeof(buffer), NULL, NULL)) + goto error; + path = buffer; +#else + path = mod.szExePath; +#endif + temp = curl_slist_append(slist, path); + if(!temp) + goto error; + slist = temp; + } while(Module32Next(hnd, &mod)); + + goto cleanup; + +error: + curl_slist_free_all(slist); + slist = NULL; +cleanup: + if(hnd != INVALID_HANDLE_VALUE) + CloseHandle(hnd); + return slist; +} + +/* The terminal settings to restore on exit */ +static struct TerminalSettings { + HANDLE hStdOut; + DWORD dwOutputMode; + LONG valid; +} TerminalSettings; + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +static void restore_terminal(void) +{ + if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE)) + SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode); +} + +/* This is the console signal handler. + * The system calls it in a separate thread. + */ +static BOOL WINAPI signal_handler(DWORD type) +{ + if(type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT) + restore_terminal(); + return FALSE; +} + +static void init_terminal(void) +{ + TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + /* + * Enable VT (Virtual Terminal) output. + * Note: VT mode flag can be set on any version of Windows, but VT + * processing only performed on Win10 >= Creators Update) + */ + if((TerminalSettings.hStdOut != INVALID_HANDLE_VALUE) && + GetConsoleMode(TerminalSettings.hStdOut, + &TerminalSettings.dwOutputMode) && + !(TerminalSettings.dwOutputMode & + ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { + /* The signal handler is set before attempting to change the console mode + because otherwise a signal would not be caught after the change but + before the handler was installed. */ + (void)InterlockedExchange(&TerminalSettings.valid, (LONG)TRUE); + if(SetConsoleCtrlHandler(signal_handler, TRUE)) { + if(SetConsoleMode(TerminalSettings.hStdOut, + (TerminalSettings.dwOutputMode | + ENABLE_VIRTUAL_TERMINAL_PROCESSING))) { + atexit(restore_terminal); + } + else { + SetConsoleCtrlHandler(signal_handler, FALSE); + (void)InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE); + } + } + } +} + +LARGE_INTEGER tool_freq; +bool tool_isVistaOrGreater; + +CURLcode win32_init(void) +{ + /* curlx_verify_windows_version must be called during init at least once + because it has its own initialization routine. */ + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) + tool_isVistaOrGreater = true; + else + tool_isVistaOrGreater = false; + + QueryPerformanceFrequency(&tool_freq); + + init_terminal(); + + return CURLE_OK; +} + +#endif /* WIN32 */ + +#endif /* MSDOS || WIN32 */ diff --git a/contrib/libs/curl/src/tool_doswin.h b/contrib/libs/curl/src/tool_doswin.h new file mode 100644 index 0000000000..ff9bad97eb --- /dev/null +++ b/contrib/libs/curl/src/tool_doswin.h @@ -0,0 +1,72 @@ +#ifndef HEADER_CURL_TOOL_DOSWIN_H +#define HEADER_CURL_TOOL_DOSWIN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(MSDOS) || defined(WIN32) + +#define SANITIZE_ALLOW_COLONS (1<<0) /* Allow colons */ +#define SANITIZE_ALLOW_PATH (1<<1) /* Allow path separators and colons */ +#define SANITIZE_ALLOW_RESERVED (1<<2) /* Allow reserved device names */ +#define SANITIZE_ALLOW_TRUNCATE (1<<3) /* Allow truncating a long filename */ + +typedef enum { + SANITIZE_ERR_OK = 0, /* 0 - OK */ + SANITIZE_ERR_INVALID_PATH, /* 1 - the path is invalid */ + SANITIZE_ERR_BAD_ARGUMENT, /* 2 - bad function parameter */ + SANITIZE_ERR_OUT_OF_MEMORY, /* 3 - out of memory */ + SANITIZE_ERR_LAST /* never use! */ +} SANITIZEcode; + +SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name, + int flags); +#ifdef UNITTESTS +SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos); +SANITIZEcode msdosify(char **const sanitized, const char *file_name, + int flags); +SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized, + const char *file_name, + int flags); +#endif /* UNITTESTS */ + +#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) + +char **__crt0_glob_function(char *arg); + +#endif /* MSDOS && (__DJGPP__ || __GO32__) */ + +#ifdef WIN32 + +CURLcode FindWin32CACert(struct OperationConfig *config, + curl_sslbackend backend, + const TCHAR *bundle_file); +struct curl_slist *GetLoadedModulePaths(void); +CURLcode win32_init(void); + +#endif /* WIN32 */ + +#endif /* MSDOS || WIN32 */ + +#endif /* HEADER_CURL_TOOL_DOSWIN_H */ diff --git a/contrib/libs/curl/src/tool_easysrc.c b/contrib/libs/curl/src/tool_easysrc.c new file mode 100644 index 0000000000..e653b31170 --- /dev/null +++ b/contrib/libs/curl/src/tool_easysrc.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "slist_wc.h" + +#ifndef CURL_DISABLE_LIBCURL_OPTION + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_easysrc.h" +#include "tool_msgs.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* global variable definitions, for easy-interface source code generation */ + +struct slist_wc *easysrc_decl = NULL; /* Variable declarations */ +struct slist_wc *easysrc_data = NULL; /* Build slists, forms etc. */ +struct slist_wc *easysrc_code = NULL; /* Setopt calls */ +struct slist_wc *easysrc_toohard = NULL; /* Unconvertible setopt */ +struct slist_wc *easysrc_clean = NULL; /* Clean up allocated data */ +int easysrc_mime_count = 0; +int easysrc_slist_count = 0; + +static const char *const srchead[]={ + "/********* Sample code generated by the curl command line tool **********", + " * All curl_easy_setopt() options are documented at:", + " * https://curl.se/libcurl/c/curl_easy_setopt.html", + " ************************************************************************/", + "#include <curl/curl.h>", + "", + "int main(int argc, char *argv[])", + "{", + " CURLcode ret;", + " CURL *hnd;", + NULL +}; +/* easysrc_decl declarations come here */ +/* easysrc_data initialization come here */ +/* easysrc_code statements come here */ +static const char *const srchard[]={ + "/* Here is a list of options the curl code used that cannot get generated", + " as source easily. You may choose to either not use them or implement", + " them yourself.", + "", + NULL +}; +static const char *const srcend[]={ + "", + " return (int)ret;", + "}", + "/**** End of sample code ****/", + NULL +}; + +/* Clean up all source code if we run out of memory */ +static void easysrc_free(void) +{ + slist_wc_free_all(easysrc_decl); + easysrc_decl = NULL; + slist_wc_free_all(easysrc_data); + easysrc_data = NULL; + slist_wc_free_all(easysrc_code); + easysrc_code = NULL; + slist_wc_free_all(easysrc_toohard); + easysrc_toohard = NULL; + slist_wc_free_all(easysrc_clean); + easysrc_clean = NULL; +} + +/* Add a source line to the main code or remarks */ +CURLcode easysrc_add(struct slist_wc **plist, const char *line) +{ + CURLcode ret = CURLE_OK; + struct slist_wc *list = slist_wc_append(*plist, line); + if(!list) { + easysrc_free(); + ret = CURLE_OUT_OF_MEMORY; + } + else + *plist = list; + return ret; +} + +CURLcode easysrc_addf(struct slist_wc **plist, const char *fmt, ...) +{ + CURLcode ret; + char *bufp; + va_list ap; + va_start(ap, fmt); + bufp = curlx_mvaprintf(fmt, ap); + va_end(ap); + if(!bufp) { + ret = CURLE_OUT_OF_MEMORY; + } + else { + ret = easysrc_add(plist, bufp); + curl_free(bufp); + } + return ret; +} + +#define CHKRET(v) do {CURLcode ret = (v); if(ret) return ret;} while(0) + +CURLcode easysrc_init(void) +{ + CHKRET(easysrc_add(&easysrc_code, + "hnd = curl_easy_init();")); + return CURLE_OK; +} + +CURLcode easysrc_perform(void) +{ + /* Note any setopt calls which we could not convert */ + if(easysrc_toohard) { + int i; + struct curl_slist *ptr; + const char *c; + CHKRET(easysrc_add(&easysrc_code, "")); + /* Preamble comment */ + for(i = 0; ((c = srchard[i]) != NULL); i++) + CHKRET(easysrc_add(&easysrc_code, c)); + /* Each unconverted option */ + if(easysrc_toohard) { + for(ptr = easysrc_toohard->first; ptr; ptr = ptr->next) + CHKRET(easysrc_add(&easysrc_code, ptr->data)); + } + CHKRET(easysrc_add(&easysrc_code, "")); + CHKRET(easysrc_add(&easysrc_code, "*/")); + + slist_wc_free_all(easysrc_toohard); + easysrc_toohard = NULL; + } + + CHKRET(easysrc_add(&easysrc_code, "")); + CHKRET(easysrc_add(&easysrc_code, "ret = curl_easy_perform(hnd);")); + CHKRET(easysrc_add(&easysrc_code, "")); + + return CURLE_OK; +} + +CURLcode easysrc_cleanup(void) +{ + CHKRET(easysrc_add(&easysrc_code, "curl_easy_cleanup(hnd);")); + CHKRET(easysrc_add(&easysrc_code, "hnd = NULL;")); + + return CURLE_OK; +} + +void dumpeasysrc(struct GlobalConfig *config) +{ + struct curl_slist *ptr; + char *o = config->libcurl; + + FILE *out; + bool fopened = FALSE; + if(strcmp(o, "-")) { + out = fopen(o, FOPEN_WRITETEXT); + fopened = TRUE; + } + else + out = stdout; + if(!out) + warnf(config, "Failed to open %s to write libcurl code!\n", o); + else { + int i; + const char *c; + + for(i = 0; ((c = srchead[i]) != NULL); i++) + fprintf(out, "%s\n", c); + + /* Declare variables used for complex setopt values */ + if(easysrc_decl) { + for(ptr = easysrc_decl->first; ptr; ptr = ptr->next) + fprintf(out, " %s\n", ptr->data); + } + + /* Set up complex values for setopt calls */ + if(easysrc_data) { + fprintf(out, "\n"); + + for(ptr = easysrc_data->first; ptr; ptr = ptr->next) + fprintf(out, " %s\n", ptr->data); + } + + fprintf(out, "\n"); + if(easysrc_code) { + for(ptr = easysrc_code->first; ptr; ptr = ptr->next) { + if(ptr->data[0]) { + fprintf(out, " %s\n", ptr->data); + } + else { + fprintf(out, "\n"); + } + } + } + + if(easysrc_clean) { + for(ptr = easysrc_clean->first; ptr; ptr = ptr->next) + fprintf(out, " %s\n", ptr->data); + } + + for(i = 0; ((c = srcend[i]) != NULL); i++) + fprintf(out, "%s\n", c); + + if(fopened) + fclose(out); + } + + easysrc_free(); +} + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ diff --git a/contrib/libs/curl/src/tool_easysrc.h b/contrib/libs/curl/src/tool_easysrc.h new file mode 100644 index 0000000000..d7a629aca7 --- /dev/null +++ b/contrib/libs/curl/src/tool_easysrc.h @@ -0,0 +1,51 @@ +#ifndef HEADER_CURL_TOOL_EASYSRC_H +#define HEADER_CURL_TOOL_EASYSRC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#ifndef CURL_DISABLE_LIBCURL_OPTION + +/* global variable declarations, for easy-interface source code generation */ + +extern struct slist_wc *easysrc_decl; /* Variable declarations */ +extern struct slist_wc *easysrc_data; /* Build slists, forms etc. */ +extern struct slist_wc *easysrc_code; /* Setopt calls etc. */ +extern struct slist_wc *easysrc_toohard; /* Unconvertible setopt */ +extern struct slist_wc *easysrc_clean; /* Clean up (reverse order) */ + +extern int easysrc_mime_count; /* Number of curl_mime variables */ +extern int easysrc_slist_count; /* Number of curl_slist variables */ + +extern CURLcode easysrc_init(void); +extern CURLcode easysrc_add(struct slist_wc **plist, const char *bupf); +extern CURLcode easysrc_addf(struct slist_wc **plist, + const char *fmt, ...); +extern CURLcode easysrc_perform(void); +extern CURLcode easysrc_cleanup(void); + +void dumpeasysrc(struct GlobalConfig *config); + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ + +#endif /* HEADER_CURL_TOOL_EASYSRC_H */ diff --git a/contrib/libs/curl/src/tool_filetime.c b/contrib/libs/curl/src/tool_filetime.c new file mode 100644 index 0000000000..c095a49eee --- /dev/null +++ b/contrib/libs/curl/src/tool_filetime.c @@ -0,0 +1,155 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_filetime.h" +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "curlx.h" + +#ifdef HAVE_UTIME_H +# include <utime.h> +#elif defined(HAVE_SYS_UTIME_H) +# include <sys/utime.h> +#endif + +curl_off_t getfiletime(const char *filename, struct GlobalConfig *global) +{ + curl_off_t result = -1; + +/* Windows stat() may attempt to adjust the unix GMT file time by a daylight + saving time offset and since it's GMT that is bad behavior. When we have + access to a 64-bit type we can bypass stat and get the times directly. */ +#if defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8) + HANDLE hfile; + TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename); + + hfile = CreateFile(tchar_filename, FILE_READ_ATTRIBUTES, + (FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE), + NULL, OPEN_EXISTING, 0, NULL); + curlx_unicodefree(tchar_filename); + if(hfile != INVALID_HANDLE_VALUE) { + FILETIME ft; + if(GetFileTime(hfile, NULL, NULL, &ft)) { + curl_off_t converted = (curl_off_t)ft.dwLowDateTime + | ((curl_off_t)ft.dwHighDateTime) << 32; + + if(converted < CURL_OFF_T_C(116444736000000000)) { + warnf(global, "Failed to get filetime: underflow\n"); + } + else { + result = (converted - CURL_OFF_T_C(116444736000000000)) / 10000000; + } + } + else { + warnf(global, "Failed to get filetime: " + "GetFileTime failed: GetLastError %u\n", + (unsigned int)GetLastError()); + } + CloseHandle(hfile); + } + else if(GetLastError() != ERROR_FILE_NOT_FOUND) { + warnf(global, "Failed to get filetime: " + "CreateFile failed: GetLastError %u\n", + (unsigned int)GetLastError()); + } +#else + struct_stat statbuf; + if(-1 != stat(filename, &statbuf)) { + result = (curl_off_t)statbuf.st_mtime; + } + else if(errno != ENOENT) { + warnf(global, "Failed to get filetime: %s\n", strerror(errno)); + } +#endif + return result; +} + +#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ + (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) +void setfiletime(curl_off_t filetime, const char *filename, + struct GlobalConfig *global) +{ + if(filetime >= 0) { +/* Windows utime() may attempt to adjust the unix GMT file time by a daylight + saving time offset and since it's GMT that is bad behavior. When we have + access to a 64-bit type we can bypass utime and set the times directly. */ +#if defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8) + HANDLE hfile; + TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename); + + /* 910670515199 is the maximum unix filetime that can be used as a + Windows FILETIME without overflow: 30827-12-31T23:59:59. */ + if(filetime > CURL_OFF_T_C(910670515199)) { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on outfile: overflow\n", filetime); + curlx_unicodefree(tchar_filename); + return; + } + + hfile = CreateFile(tchar_filename, FILE_WRITE_ATTRIBUTES, + (FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE), + NULL, OPEN_EXISTING, 0, NULL); + curlx_unicodefree(tchar_filename); + if(hfile != INVALID_HANDLE_VALUE) { + curl_off_t converted = ((curl_off_t)filetime * 10000000) + + CURL_OFF_T_C(116444736000000000); + FILETIME ft; + ft.dwLowDateTime = (DWORD)(converted & 0xFFFFFFFF); + ft.dwHighDateTime = (DWORD)(converted >> 32); + if(!SetFileTime(hfile, NULL, &ft, &ft)) { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on outfile: SetFileTime failed: GetLastError %u\n", + filetime, (unsigned int)GetLastError()); + } + CloseHandle(hfile); + } + else { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on outfile: CreateFile failed: GetLastError %u\n", + filetime, (unsigned int)GetLastError()); + } + +#elif defined(HAVE_UTIMES) + struct timeval times[2]; + times[0].tv_sec = times[1].tv_sec = (time_t)filetime; + times[0].tv_usec = times[1].tv_usec = 0; + if(utimes(filename, times)) { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on '%s': %s\n", filetime, filename, strerror(errno)); + } + +#elif defined(HAVE_UTIME) + struct utimbuf times; + times.actime = (time_t)filetime; + times.modtime = (time_t)filetime; + if(utime(filename, ×)) { + warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T + " on '%s': %s\n", filetime, filename, strerror(errno)); + } +#endif + } +} +#endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ + (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */ diff --git a/contrib/libs/curl/src/tool_filetime.h b/contrib/libs/curl/src/tool_filetime.h new file mode 100644 index 0000000000..3d88d8913b --- /dev/null +++ b/contrib/libs/curl/src/tool_filetime.h @@ -0,0 +1,41 @@ +#ifndef HEADER_CURL_TOOL_FILETIME_H +#define HEADER_CURL_TOOL_FILETIME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +struct GlobalConfig; + +curl_off_t getfiletime(const char *filename, struct GlobalConfig *global); + +#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ + (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) +void setfiletime(curl_off_t filetime, const char *filename, + struct GlobalConfig *global); +#else +#define setfiletime(a,b,c) Curl_nop_stmt +#endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \ + (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */ + +#endif /* HEADER_CURL_TOOL_FILETIME_H */ diff --git a/contrib/libs/curl/src/tool_findfile.c b/contrib/libs/curl/src/tool_findfile.c new file mode 100644 index 0000000000..51a45ff3a0 --- /dev/null +++ b/contrib/libs/curl/src/tool_findfile.c @@ -0,0 +1,157 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_PWD_H +# undef __NO_NET_API /* required for building for AmigaOS */ +# include <pwd.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#include <curl/mprintf.h> + +#include "tool_findfile.h" + +#include "memdebug.h" /* keep this as LAST include */ + +struct finder { + const char *env; + const char *append; + bool withoutdot; +}; + +/* The order of the variables below is important, as the index number is used + in the findfile() function */ +static const struct finder list[] = { + { "CURL_HOME", NULL, FALSE }, + { "XDG_CONFIG_HOME", NULL, FALSE }, /* index == 1, used in the code */ + { "HOME", NULL, FALSE }, +#ifdef WIN32 + { "USERPROFILE", NULL, FALSE }, + { "APPDATA", NULL, FALSE }, + { "USERPROFILE", "\\Application Data", FALSE}, +#endif + /* these are for .curlrc if XDG_CONFIG_HOME is not defined */ + { "CURL_HOME", "/.config", TRUE }, + { "HOME", "/.config", TRUE }, + + { NULL, NULL, FALSE } +}; + +static char *checkhome(const char *home, const char *fname, bool dotscore) +{ + const char pref[2] = { '.', '_' }; + int i; + for(i = 0; i < (dotscore ? 2 : 1); i++) { + char *c; + if(dotscore) + c = curl_maprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]); + else + c = curl_maprintf("%s" DIR_CHAR "%s", home, fname); + if(c) { + int fd = open(c, O_RDONLY); + if(fd >= 0) { + char *path = strdup(c); + close(fd); + curl_free(c); + return path; + } + curl_free(c); + } + } + return NULL; +} + +/* + * findfile() - return the full path name of the file. + * + * If 'dotscore' is TRUE, then check for the file first with a leading dot + * and then with a leading underscore. + * + * 1. Iterate over the environment variables in order, and if set, check for + * the given file to be accessed there, then it is a match. + * 2. Non-windows: try getpwuid + */ +char *findfile(const char *fname, int dotscore) +{ + int i; + bool xdg = FALSE; + DEBUGASSERT(fname && fname[0]); + DEBUGASSERT((dotscore != 1) || (fname[0] == '.')); + + if(!fname[0]) + return NULL; + + for(i = 0; list[i].env; i++) { + char *home = curl_getenv(list[i].env); + if(home) { + char *path; + const char *filename = fname; + if(i == 1 /* XDG_CONFIG_HOME */) + xdg = TRUE; + if(!home[0]) { + curl_free(home); + continue; + } + if(list[i].append) { + char *c = curl_maprintf("%s%s", home, list[i].append); + curl_free(home); + if(!c) + return NULL; + home = c; + } + if(list[i].withoutdot) { + if(!dotscore || xdg) { + /* this is not looking for .curlrc, or the XDG_CONFIG_HOME was + defined so we skip the extended check */ + curl_free(home); + continue; + } + filename++; /* move past the leading dot */ + dotscore = 0; /* disable it for this check */ + } + path = checkhome(home, filename, dotscore ? dotscore - 1 : 0); + curl_free(home); + if(path) + return path; + } + } +#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) + { + struct passwd *pw = getpwuid(geteuid()); + if(pw) { + char *home = pw->pw_dir; + if(home && home[0]) + return checkhome(home, fname, FALSE); + } + } +#endif /* PWD-stuff */ + return NULL; +} diff --git a/contrib/libs/curl/src/tool_findfile.h b/contrib/libs/curl/src/tool_findfile.h new file mode 100644 index 0000000000..5bae579e14 --- /dev/null +++ b/contrib/libs/curl/src/tool_findfile.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_HOMEDIR_H +#define HEADER_CURL_TOOL_HOMEDIR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef WIN32 +#define CURLRC_DOTSCORE 2 /* look for underscore-prefixed name too */ +#else +#define CURLRC_DOTSCORE 1 /* regular .curlrc check */ +#endif + +char *findfile(const char *fname, int dotscore); + +#endif /* HEADER_CURL_TOOL_HOMEDIR_H */ diff --git a/contrib/libs/curl/src/tool_formparse.c b/contrib/libs/curl/src/tool_formparse.c new file mode 100644 index 0000000000..927d3c1492 --- /dev/null +++ b/contrib/libs/curl/src/tool_formparse.c @@ -0,0 +1,913 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_binmode.h" +#include "tool_getparam.h" +#include "tool_paramhlp.h" +#include "tool_formparse.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* Macros to free const pointers. */ +#define CONST_FREE(x) free((void *) (x)) +#define CONST_SAFEFREE(x) Curl_safefree(*((void **) &(x))) + +/* tool_mime functions. */ +static struct tool_mime *tool_mime_new(struct tool_mime *parent, + toolmimekind kind) +{ + struct tool_mime *m = (struct tool_mime *) calloc(1, sizeof(*m)); + + if(m) { + m->kind = kind; + m->parent = parent; + if(parent) { + m->prev = parent->subparts; + parent->subparts = m; + } + } + return m; +} + +static struct tool_mime *tool_mime_new_parts(struct tool_mime *parent) +{ + return tool_mime_new(parent, TOOLMIME_PARTS); +} + +static struct tool_mime *tool_mime_new_data(struct tool_mime *parent, + const char *data) +{ + struct tool_mime *m = NULL; + + data = strdup(data); + if(data) { + m = tool_mime_new(parent, TOOLMIME_DATA); + if(!m) + CONST_FREE(data); + else + m->data = data; + } + return m; +} + +static struct tool_mime *tool_mime_new_filedata(struct tool_mime *parent, + const char *filename, + bool isremotefile, + CURLcode *errcode) +{ + CURLcode result = CURLE_OK; + struct tool_mime *m = NULL; + + *errcode = CURLE_OUT_OF_MEMORY; + if(strcmp(filename, "-")) { + /* This is a normal file. */ + filename = strdup(filename); + if(filename) { + m = tool_mime_new(parent, TOOLMIME_FILE); + if(!m) + CONST_FREE(filename); + else { + m->data = filename; + if(!isremotefile) + m->kind = TOOLMIME_FILEDATA; + *errcode = CURLE_OK; + } + } + } + else { /* Standard input. */ + int fd = fileno(stdin); + char *data = NULL; + curl_off_t size; + curl_off_t origin; + struct_stat sbuf; + + set_binmode(stdin); + origin = ftell(stdin); + /* If stdin is a regular file, do not buffer data but read it + when needed. */ + if(fd >= 0 && origin >= 0 && !fstat(fd, &sbuf) && +#ifdef __VMS + sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC && +#endif + S_ISREG(sbuf.st_mode)) { + size = sbuf.st_size - origin; + if(size < 0) + size = 0; + } + else { /* Not suitable for direct use, buffer stdin data. */ + size_t stdinsize = 0; + + switch(file2memory(&data, &stdinsize, stdin)) { + case PARAM_NO_MEM: + return m; + case PARAM_READ_ERROR: + result = CURLE_READ_ERROR; + break; + default: + if(!stdinsize) { + /* Zero-length data has been freed. Re-create it. */ + data = strdup(""); + if(!data) + return m; + } + break; + } + size = curlx_uztoso(stdinsize); + origin = 0; + } + m = tool_mime_new(parent, TOOLMIME_STDIN); + if(!m) + Curl_safefree(data); + else { + m->data = data; + m->origin = origin; + m->size = size; + m->curpos = 0; + if(!isremotefile) + m->kind = TOOLMIME_STDINDATA; + *errcode = result; + } + } + return m; +} + +void tool_mime_free(struct tool_mime *mime) +{ + if(mime) { + if(mime->subparts) + tool_mime_free(mime->subparts); + if(mime->prev) + tool_mime_free(mime->prev); + CONST_SAFEFREE(mime->name); + CONST_SAFEFREE(mime->filename); + CONST_SAFEFREE(mime->type); + CONST_SAFEFREE(mime->encoder); + CONST_SAFEFREE(mime->data); + curl_slist_free_all(mime->headers); + free(mime); + } +} + + +/* Mime part callbacks for stdin. */ +size_t tool_mime_stdin_read(char *buffer, + size_t size, size_t nitems, void *arg) +{ + struct tool_mime *sip = (struct tool_mime *) arg; + curl_off_t bytesleft; + (void) size; /* Always 1: ignored. */ + + if(sip->size >= 0) { + if(sip->curpos >= sip->size) + return 0; /* At eof. */ + bytesleft = sip->size - sip->curpos; + if(curlx_uztoso(nitems) > bytesleft) + nitems = curlx_sotouz(bytesleft); + } + if(nitems) { + if(sip->data) { + /* Return data from memory. */ + memcpy(buffer, sip->data + curlx_sotouz(sip->curpos), nitems); + } + else { + /* Read from stdin. */ + nitems = fread(buffer, 1, nitems, stdin); + if(ferror(stdin)) { + /* Show error only once. */ + if(sip->config) { + warnf(sip->config, "stdin: %s\n", strerror(errno)); + sip->config = NULL; + } + return CURL_READFUNC_ABORT; + } + } + sip->curpos += curlx_uztoso(nitems); + } + return nitems; +} + +int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence) +{ + struct tool_mime *sip = (struct tool_mime *) instream; + + switch(whence) { + case SEEK_CUR: + offset += sip->curpos; + break; + case SEEK_END: + offset += sip->size; + break; + } + if(offset < 0) + return CURL_SEEKFUNC_CANTSEEK; + if(!sip->data) { + if(fseek(stdin, (long) (offset + sip->origin), SEEK_SET)) + return CURL_SEEKFUNC_CANTSEEK; + } + sip->curpos = offset; + return CURL_SEEKFUNC_OK; +} + +/* Translate an internal mime tree into a libcurl mime tree. */ + +static CURLcode tool2curlparts(CURL *curl, struct tool_mime *m, + curl_mime *mime) +{ + CURLcode ret = CURLE_OK; + curl_mimepart *part = NULL; + curl_mime *submime = NULL; + const char *filename = NULL; + + if(m) { + ret = tool2curlparts(curl, m->prev, mime); + if(!ret) { + part = curl_mime_addpart(mime); + if(!part) + ret = CURLE_OUT_OF_MEMORY; + } + if(!ret) { + filename = m->filename; + switch(m->kind) { + case TOOLMIME_PARTS: + ret = tool2curlmime(curl, m, &submime); + if(!ret) { + ret = curl_mime_subparts(part, submime); + if(ret) + curl_mime_free(submime); + } + break; + + case TOOLMIME_DATA: + ret = curl_mime_data(part, m->data, CURL_ZERO_TERMINATED); + break; + + case TOOLMIME_FILE: + case TOOLMIME_FILEDATA: + ret = curl_mime_filedata(part, m->data); + if(!ret && m->kind == TOOLMIME_FILEDATA && !filename) + ret = curl_mime_filename(part, NULL); + break; + + case TOOLMIME_STDIN: + if(!filename) + filename = "-"; + /* FALLTHROUGH */ + case TOOLMIME_STDINDATA: + ret = curl_mime_data_cb(part, m->size, + (curl_read_callback) tool_mime_stdin_read, + (curl_seek_callback) tool_mime_stdin_seek, + NULL, m); + break; + + default: + /* Other cases not possible in this context. */ + break; + } + } + if(!ret && filename) + ret = curl_mime_filename(part, filename); + if(!ret) + ret = curl_mime_type(part, m->type); + if(!ret) + ret = curl_mime_headers(part, m->headers, 0); + if(!ret) + ret = curl_mime_encoder(part, m->encoder); + if(!ret) + ret = curl_mime_name(part, m->name); + } + return ret; +} + +CURLcode tool2curlmime(CURL *curl, struct tool_mime *m, curl_mime **mime) +{ + CURLcode ret = CURLE_OK; + + *mime = curl_mime_init(curl); + if(!*mime) + ret = CURLE_OUT_OF_MEMORY; + else + ret = tool2curlparts(curl, m->subparts, *mime); + if(ret) { + curl_mime_free(*mime); + *mime = NULL; + } + return ret; +} + +/* + * helper function to get a word from form param + * after call get_parm_word, str either point to string end + * or point to any of end chars. + */ +static char *get_param_word(struct OperationConfig *config, char **str, + char **end_pos, char endchar) +{ + char *ptr = *str; + /* the first non-space char is here */ + char *word_begin = ptr; + char *ptr2; + char *escape = NULL; + + if(*ptr == '"') { + ++ptr; + while(*ptr) { + if(*ptr == '\\') { + if(ptr[1] == '\\' || ptr[1] == '"') { + /* remember the first escape position */ + if(!escape) + escape = ptr; + /* skip escape of back-slash or double-quote */ + ptr += 2; + continue; + } + } + if(*ptr == '"') { + bool trailing_data = FALSE; + *end_pos = ptr; + if(escape) { + /* has escape, we restore the unescaped string here */ + ptr = ptr2 = escape; + do { + if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"')) + ++ptr; + *ptr2++ = *ptr++; + } + while(ptr < *end_pos); + *end_pos = ptr2; + } + ++ptr; + while(*ptr && *ptr != ';' && *ptr != endchar) { + if(!ISSPACE(*ptr)) + trailing_data = TRUE; + ++ptr; + } + if(trailing_data) + warnf(config->global, "Trailing data after quoted form parameter\n"); + *str = ptr; + return word_begin + 1; + } + ++ptr; + } + /* end quote is missing, treat it as non-quoted. */ + ptr = word_begin; + } + + while(*ptr && *ptr != ';' && *ptr != endchar) + ++ptr; + *str = *end_pos = ptr; + return word_begin; +} + +/* Append slist item and return -1 if failed. */ +static int slist_append(struct curl_slist **plist, const char *data) +{ + struct curl_slist *s = curl_slist_append(*plist, data); + + if(!s) + return -1; + + *plist = s; + return 0; +} + +/* Read headers from a file and append to list. */ +static int read_field_headers(struct OperationConfig *config, + const char *filename, FILE *fp, + struct curl_slist **pheaders) +{ + size_t hdrlen = 0; + size_t pos = 0; + bool incomment = FALSE; + int lineno = 1; + char hdrbuf[999] = ""; /* Max. header length + 1. */ + + for(;;) { + int c = getc(fp); + if(c == EOF || (!pos && !ISSPACE(c))) { + /* Strip and flush the current header. */ + while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1])) + hdrlen--; + if(hdrlen) { + hdrbuf[hdrlen] = '\0'; + if(slist_append(pheaders, hdrbuf)) { + fprintf(config->global->errors, + "Out of memory for field headers!\n"); + return -1; + } + hdrlen = 0; + } + } + + switch(c) { + case EOF: + if(ferror(fp)) { + fprintf(config->global->errors, + "Header file %s read error: %s\n", filename, strerror(errno)); + return -1; + } + return 0; /* Done. */ + case '\r': + continue; /* Ignore. */ + case '\n': + pos = 0; + incomment = FALSE; + lineno++; + continue; + case '#': + if(!pos) + incomment = TRUE; + break; + } + + pos++; + if(!incomment) { + if(hdrlen == sizeof(hdrbuf) - 1) { + warnf(config->global, "File %s line %d: header too long (truncated)\n", + filename, lineno); + c = ' '; + } + if(hdrlen <= sizeof(hdrbuf) - 1) + hdrbuf[hdrlen++] = (char) c; + } + } + /* NOTREACHED */ +} + +static int get_param_part(struct OperationConfig *config, char endchar, + char **str, char **pdata, char **ptype, + char **pfilename, char **pencoder, + struct curl_slist **pheaders) +{ + char *p = *str; + char *type = NULL; + char *filename = NULL; + char *encoder = NULL; + char *endpos; + char *tp; + char sep; + char type_major[128] = ""; + char type_minor[128] = ""; + char *endct = NULL; + struct curl_slist *headers = NULL; + + if(ptype) + *ptype = NULL; + if(pfilename) + *pfilename = NULL; + if(pheaders) + *pheaders = NULL; + if(pencoder) + *pencoder = NULL; + while(ISSPACE(*p)) + p++; + tp = p; + *pdata = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(*pdata == tp) + while(endpos > *pdata && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + while(sep == ';') { + while(ISSPACE(*++p)) + ; + + if(!endct && checkprefix("type=", p)) { + for(p += 5; ISSPACE(*p); p++) + ; + /* set type pointer */ + type = p; + + /* verify that this is a fine type specifier */ + if(2 != sscanf(type, "%127[^/ ]/%127[^;, \n]", type_major, type_minor)) { + warnf(config->global, "Illegally formatted content-type field!\n"); + curl_slist_free_all(headers); + return -1; /* illegal content-type syntax! */ + } + + /* now point beyond the content-type specifier */ + p = type + strlen(type_major) + strlen(type_minor) + 1; + for(endct = p; *p && *p != ';' && *p != endchar; p++) + if(!ISSPACE(*p)) + endct = p + 1; + sep = *p; + } + else if(checkprefix("filename=", p)) { + if(endct) { + *endct = '\0'; + endct = NULL; + } + for(p += 9; ISSPACE(*p); p++) + ; + tp = p; + filename = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(filename == tp) + while(endpos > filename && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + } + else if(checkprefix("headers=", p)) { + if(endct) { + *endct = '\0'; + endct = NULL; + } + p += 8; + if(*p == '@' || *p == '<') { + char *hdrfile; + FILE *fp; + /* Read headers from a file. */ + + do { + p++; + } while(ISSPACE(*p)); + tp = p; + hdrfile = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(hdrfile == tp) + while(endpos > hdrfile && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + fp = fopen(hdrfile, FOPEN_READTEXT); + if(!fp) + warnf(config->global, "Cannot read from %s: %s\n", hdrfile, + strerror(errno)); + else { + int i = read_field_headers(config, hdrfile, fp, &headers); + + fclose(fp); + if(i) { + curl_slist_free_all(headers); + return -1; + } + } + } + else { + char *hdr; + + while(ISSPACE(*p)) + p++; + tp = p; + hdr = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(hdr == tp) + while(endpos > hdr && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + if(slist_append(&headers, hdr)) { + fprintf(config->global->errors, "Out of memory for field header!\n"); + curl_slist_free_all(headers); + return -1; + } + } + } + else if(checkprefix("encoder=", p)) { + if(endct) { + *endct = '\0'; + endct = NULL; + } + for(p += 8; ISSPACE(*p); p++) + ; + tp = p; + encoder = get_param_word(config, &p, &endpos, endchar); + /* If not quoted, strip trailing spaces. */ + if(encoder == tp) + while(endpos > encoder && ISSPACE(endpos[-1])) + endpos--; + sep = *p; + *endpos = '\0'; + } + else if(endct) { + /* This is part of content type. */ + for(endct = p; *p && *p != ';' && *p != endchar; p++) + if(!ISSPACE(*p)) + endct = p + 1; + sep = *p; + } + else { + /* unknown prefix, skip to next block */ + char *unknown = get_param_word(config, &p, &endpos, endchar); + + sep = *p; + *endpos = '\0'; + if(*unknown) + warnf(config->global, "skip unknown form field: %s\n", unknown); + } + } + + /* Terminate content type. */ + if(endct) + *endct = '\0'; + + if(ptype) + *ptype = type; + else if(type) + warnf(config->global, "Field content type not allowed here: %s\n", type); + + if(pfilename) + *pfilename = filename; + else if(filename) + warnf(config->global, + "Field file name not allowed here: %s\n", filename); + + if(pencoder) + *pencoder = encoder; + else if(encoder) + warnf(config->global, + "Field encoder not allowed here: %s\n", encoder); + + if(pheaders) + *pheaders = headers; + else if(headers) { + warnf(config->global, + "Field headers not allowed here: %s\n", headers->data); + curl_slist_free_all(headers); + } + + *str = p; + return sep & 0xFF; +} + + +/*************************************************************************** + * + * formparse() + * + * Reads a 'name=value' parameter and builds the appropriate linked list. + * + * If the value is of the form '<filename', field data is read from the + * given file. + + * Specify files to upload with 'name=@filename', or 'name=@"filename"' + * in case the filename contain ',' or ';'. Supports specified + * given Content-Type of the files. Such as ';type=<content-type>'. + * + * If literal_value is set, any initial '@' or '<' in the value string + * loses its special meaning, as does any embedded ';type='. + * + * You may specify more than one file for a single name (field). Specify + * multiple files by writing it like: + * + * 'name=@filename,filename2,filename3' + * + * or use double-quotes quote the filename: + * + * 'name=@"filename","filename2","filename3"' + * + * If you want content-types specified for each too, write them like: + * + * 'name=@filename;type=image/gif,filename2,filename3' + * + * If you want custom headers added for a single part, write them in a separate + * file and do like this: + * + * 'name=foo;headers=@headerfile' or why not + * 'name=@filemame;headers=@headerfile' + * + * To upload a file, but to fake the file name that will be included in the + * formpost, do like this: + * + * 'name=@filename;filename=/dev/null' or quote the faked filename like: + * 'name=@filename;filename="play, play, and play.txt"' + * + * If filename/path contains ',' or ';', it must be quoted by double-quotes, + * else curl will fail to figure out the correct filename. if the filename + * tobe quoted contains '"' or '\', '"' and '\' must be escaped by backslash. + * + ***************************************************************************/ + +/* Convenience macros for null pointer check. */ +#define NULL_CHECK(ptr, init, retcode) \ + do { \ + (ptr) = (init); \ + if(!(ptr)) { \ + warnf(config->global, "out of memory!\n"); \ + curl_slist_free_all(headers); \ + Curl_safefree(contents); \ + return retcode; \ + } \ + } while(0) + +#define SET_TOOL_MIME_PTR(m, field, retcode) \ + do { \ + if(field) \ + NULL_CHECK((m)->field, strdup(field), retcode); \ + } while(0) + +int formparse(struct OperationConfig *config, + const char *input, + struct tool_mime **mimeroot, + struct tool_mime **mimecurrent, + bool literal_value) +{ + /* input MUST be a string in the format 'name=contents' and we'll + build a linked list with the info */ + char *name = NULL; + char *contents = NULL; + char *contp; + char *data; + char *type = NULL; + char *filename = NULL; + char *encoder = NULL; + struct curl_slist *headers = NULL; + struct tool_mime *part = NULL; + CURLcode res; + + /* Allocate the main mime structure if needed. */ + if(!*mimecurrent) { + NULL_CHECK(*mimeroot, tool_mime_new_parts(NULL), 1); + *mimecurrent = *mimeroot; + } + + /* Make a copy we can overwrite. */ + NULL_CHECK(contents, strdup(input), 2); + + /* Scan for the end of the name. */ + contp = strchr(contents, '='); + if(contp) { + int sep = '\0'; + if(contp > contents) + name = contents; + *contp++ = '\0'; + + if(*contp == '(' && !literal_value) { + /* Starting a multipart. */ + sep = get_param_part(config, '\0', + &contp, &data, &type, NULL, NULL, &headers); + if(sep < 0) { + Curl_safefree(contents); + return 3; + } + NULL_CHECK(part, tool_mime_new_parts(*mimecurrent), 4); + *mimecurrent = part; + part->headers = headers; + headers = NULL; + SET_TOOL_MIME_PTR(part, type, 5); + } + else if(!name && !strcmp(contp, ")") && !literal_value) { + /* Ending a multipart. */ + if(*mimecurrent == *mimeroot) { + warnf(config->global, "no multipart to terminate!\n"); + Curl_safefree(contents); + return 6; + } + *mimecurrent = (*mimecurrent)->parent; + } + else if('@' == contp[0] && !literal_value) { + + /* we use the @-letter to indicate file name(s) */ + + struct tool_mime *subparts = NULL; + + do { + /* since this was a file, it may have a content-type specifier + at the end too, or a filename. Or both. */ + ++contp; + sep = get_param_part(config, ',', &contp, + &data, &type, &filename, &encoder, &headers); + if(sep < 0) { + Curl_safefree(contents); + return 7; + } + + /* now contp point to comma or string end. + If more files to come, make sure we have multiparts. */ + if(!subparts) { + if(sep != ',') /* If there is a single file. */ + subparts = *mimecurrent; + else + NULL_CHECK(subparts, tool_mime_new_parts(*mimecurrent), 8); + } + + /* Store that file in a part. */ + NULL_CHECK(part, + tool_mime_new_filedata(subparts, data, TRUE, &res), 9); + part->headers = headers; + headers = NULL; + part->config = config->global; + if(res == CURLE_READ_ERROR) { + /* An error occurred while reading stdin: if read has started, + issue the error now. Else, delay it until processed by + libcurl. */ + if(part->size > 0) { + warnf(config->global, + "error while reading standard input\n"); + Curl_safefree(contents); + return 10; + } + CONST_SAFEFREE(part->data); + part->data = NULL; + part->size = -1; + res = CURLE_OK; + } + SET_TOOL_MIME_PTR(part, filename, 11); + SET_TOOL_MIME_PTR(part, type, 12); + SET_TOOL_MIME_PTR(part, encoder, 13); + + /* *contp could be '\0', so we just check with the delimiter */ + } while(sep); /* loop if there's another file name */ + part = (*mimecurrent)->subparts; /* Set name on group. */ + } + else { + if(*contp == '<' && !literal_value) { + ++contp; + sep = get_param_part(config, '\0', &contp, + &data, &type, NULL, &encoder, &headers); + if(sep < 0) { + Curl_safefree(contents); + return 14; + } + + NULL_CHECK(part, tool_mime_new_filedata(*mimecurrent, data, FALSE, + &res), 15); + part->headers = headers; + headers = NULL; + part->config = config->global; + if(res == CURLE_READ_ERROR) { + /* An error occurred while reading stdin: if read has started, + issue the error now. Else, delay it until processed by + libcurl. */ + if(part->size > 0) { + warnf(config->global, + "error while reading standard input\n"); + Curl_safefree(contents); + return 16; + } + CONST_SAFEFREE(part->data); + part->data = NULL; + part->size = -1; + res = CURLE_OK; + } + } + else { + if(literal_value) + data = contp; + else { + sep = get_param_part(config, '\0', &contp, + &data, &type, &filename, &encoder, &headers); + if(sep < 0) { + Curl_safefree(contents); + return 17; + } + } + + NULL_CHECK(part, tool_mime_new_data(*mimecurrent, data), 18); + part->headers = headers; + headers = NULL; + } + + SET_TOOL_MIME_PTR(part, filename, 19); + SET_TOOL_MIME_PTR(part, type, 20); + SET_TOOL_MIME_PTR(part, encoder, 21); + + if(sep) { + *contp = (char) sep; + warnf(config->global, + "garbage at end of field specification: %s\n", contp); + } + } + + /* Set part name. */ + SET_TOOL_MIME_PTR(part, name, 22); + } + else { + warnf(config->global, "Illegally formatted input field!\n"); + Curl_safefree(contents); + return 23; + } + Curl_safefree(contents); + return 0; +} diff --git a/contrib/libs/curl/src/tool_formparse.h b/contrib/libs/curl/src/tool_formparse.h new file mode 100644 index 0000000000..260bcf48f0 --- /dev/null +++ b/contrib/libs/curl/src/tool_formparse.h @@ -0,0 +1,73 @@ +#ifndef HEADER_CURL_TOOL_FORMPARSE_H +#define HEADER_CURL_TOOL_FORMPARSE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* Private structure for mime/parts. */ + +typedef enum { + TOOLMIME_NONE = 0, + TOOLMIME_PARTS, + TOOLMIME_DATA, + TOOLMIME_FILE, + TOOLMIME_FILEDATA, + TOOLMIME_STDIN, + TOOLMIME_STDINDATA +} toolmimekind; + +struct tool_mime { + /* Structural fields. */ + toolmimekind kind; /* Part kind. */ + struct tool_mime *parent; /* Parent item. */ + struct tool_mime *prev; /* Previous sibling (reverse order link). */ + /* Common fields. */ + const char *data; /* Actual data or data filename. */ + const char *name; /* Part name. */ + const char *filename; /* Part's filename. */ + const char *type; /* Part's mime type. */ + const char *encoder; /* Part's requested encoding. */ + struct curl_slist *headers; /* User-defined headers. */ + /* TOOLMIME_PARTS fields. */ + struct tool_mime *subparts; /* Part's subparts. */ + /* TOOLMIME_STDIN/TOOLMIME_STDINDATA fields. */ + curl_off_t origin; /* Stdin read origin offset. */ + curl_off_t size; /* Stdin data size. */ + curl_off_t curpos; /* Stdin current read position. */ + struct GlobalConfig *config; /* For access from callback. */ +}; + +size_t tool_mime_stdin_read(char *buffer, + size_t size, size_t nitems, void *arg); +int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence); + +int formparse(struct OperationConfig *config, + const char *input, + struct tool_mime **mimeroot, + struct tool_mime **mimecurrent, + bool literal_value); +CURLcode tool2curlmime(CURL *curl, struct tool_mime *m, curl_mime **mime); +void tool_mime_free(struct tool_mime *mime); + +#endif /* HEADER_CURL_TOOL_FORMPARSE_H */ diff --git a/contrib/libs/curl/src/tool_getparam.c b/contrib/libs/curl/src/tool_getparam.c new file mode 100644 index 0000000000..e6c6a273da --- /dev/null +++ b/contrib/libs/curl/src/tool_getparam.c @@ -0,0 +1,2525 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_binmode.h" +#include "tool_cfgable.h" +#include "tool_cb_prg.h" +#include "tool_filetime.h" +#include "tool_formparse.h" +#include "tool_getparam.h" +#include "tool_helpers.h" +#include "tool_libinfo.h" +#include "tool_msgs.h" +#include "tool_paramhlp.h" +#include "tool_parsecfg.h" +#include "tool_main.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef MSDOS +# define USE_WATT32 +#endif + +#define GetStr(str,val) do { \ + if(*(str)) { \ + free(*(str)); \ + *(str) = NULL; \ + } \ + if((val)) { \ + *(str) = strdup((val)); \ + if(!(*(str))) \ + return PARAM_NO_MEM; \ + } \ +} while(0) + +struct LongShort { + const char *letter; /* short name option */ + const char *lname; /* long name option */ + enum { + ARG_NONE, /* stand-alone but not a boolean */ + ARG_BOOL, /* accepts a --no-[name] prefix */ + ARG_STRING, /* requires an argument */ + ARG_FILENAME /* requires an argument, usually a file name */ + } desc; +}; + +static const struct LongShort aliases[]= { + /* 'letter' strings with more than one character have *no* short option to + mention. */ + {"*@", "url", ARG_STRING}, + {"*4", "dns-ipv4-addr", ARG_STRING}, + {"*6", "dns-ipv6-addr", ARG_STRING}, + {"*a", "random-file", ARG_FILENAME}, + {"*b", "egd-file", ARG_STRING}, + {"*B", "oauth2-bearer", ARG_STRING}, + {"*c", "connect-timeout", ARG_STRING}, + {"*C", "doh-url" , ARG_STRING}, + {"*d", "ciphers", ARG_STRING}, + {"*D", "dns-interface", ARG_STRING}, + {"*e", "disable-epsv", ARG_BOOL}, + {"*f", "disallow-username-in-url", ARG_BOOL}, + {"*E", "epsv", ARG_BOOL}, + /* 'epsv' made like this to make --no-epsv and --epsv to work + although --disable-epsv is the documented option */ + {"*F", "dns-servers", ARG_STRING}, + {"*g", "trace", ARG_FILENAME}, + {"*G", "npn", ARG_BOOL}, + {"*h", "trace-ascii", ARG_FILENAME}, + {"*H", "alpn", ARG_BOOL}, + {"*i", "limit-rate", ARG_STRING}, + {"*I", "rate", ARG_STRING}, + {"*j", "compressed", ARG_BOOL}, + {"*J", "tr-encoding", ARG_BOOL}, + {"*k", "digest", ARG_BOOL}, + {"*l", "negotiate", ARG_BOOL}, + {"*m", "ntlm", ARG_BOOL}, + {"*M", "ntlm-wb", ARG_BOOL}, + {"*n", "basic", ARG_BOOL}, + {"*o", "anyauth", ARG_BOOL}, +#ifdef USE_WATT32 + {"*p", "wdebug", ARG_BOOL}, +#endif + {"*q", "ftp-create-dirs", ARG_BOOL}, + {"*r", "create-dirs", ARG_BOOL}, + {"*R", "create-file-mode", ARG_STRING}, + {"*s", "max-redirs", ARG_STRING}, + {"*t", "proxy-ntlm", ARG_BOOL}, + {"*u", "crlf", ARG_BOOL}, + {"*v", "stderr", ARG_FILENAME}, + {"*V", "aws-sigv4", ARG_STRING}, + {"*w", "interface", ARG_STRING}, + {"*x", "krb", ARG_STRING}, + {"*x", "krb4", ARG_STRING}, + /* 'krb4' is the previous name */ + {"*X", "haproxy-protocol", ARG_BOOL}, + {"*y", "max-filesize", ARG_STRING}, + {"*z", "disable-eprt", ARG_BOOL}, + {"*Z", "eprt", ARG_BOOL}, + /* 'eprt' made like this to make --no-eprt and --eprt to work + although --disable-eprt is the documented option */ + {"*~", "xattr", ARG_BOOL}, + {"$a", "ftp-ssl", ARG_BOOL}, + /* 'ftp-ssl' deprecated name since 7.20.0 */ + {"$a", "ssl", ARG_BOOL}, + /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */ + {"$b", "ftp-pasv", ARG_BOOL}, + {"$c", "socks5", ARG_STRING}, + {"$d", "tcp-nodelay", ARG_BOOL}, + {"$e", "proxy-digest", ARG_BOOL}, + {"$f", "proxy-basic", ARG_BOOL}, + {"$g", "retry", ARG_STRING}, + {"$V", "retry-connrefused", ARG_BOOL}, + {"$h", "retry-delay", ARG_STRING}, + {"$i", "retry-max-time", ARG_STRING}, + {"$k", "proxy-negotiate", ARG_BOOL}, + {"$l", "form-escape", ARG_BOOL}, + {"$m", "ftp-account", ARG_STRING}, + {"$n", "proxy-anyauth", ARG_BOOL}, + {"$o", "trace-time", ARG_BOOL}, + {"$p", "ignore-content-length", ARG_BOOL}, + {"$q", "ftp-skip-pasv-ip", ARG_BOOL}, + {"$r", "ftp-method", ARG_STRING}, + {"$s", "local-port", ARG_STRING}, + {"$t", "socks4", ARG_STRING}, + {"$T", "socks4a", ARG_STRING}, + {"$u", "ftp-alternative-to-user", ARG_STRING}, + {"$v", "ftp-ssl-reqd", ARG_BOOL}, + /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */ + {"$v", "ssl-reqd", ARG_BOOL}, + /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */ + {"$w", "sessionid", ARG_BOOL}, + /* 'sessionid' listed as --no-sessionid in the help */ + {"$x", "ftp-ssl-control", ARG_BOOL}, + {"$y", "ftp-ssl-ccc", ARG_BOOL}, + {"$j", "ftp-ssl-ccc-mode", ARG_STRING}, + {"$z", "libcurl", ARG_STRING}, + {"$#", "raw", ARG_BOOL}, + {"$0", "post301", ARG_BOOL}, + {"$1", "keepalive", ARG_BOOL}, + /* 'keepalive' listed as --no-keepalive in the help */ + {"$2", "socks5-hostname", ARG_STRING}, + {"$3", "keepalive-time", ARG_STRING}, + {"$4", "post302", ARG_BOOL}, + {"$5", "noproxy", ARG_STRING}, + {"$7", "socks5-gssapi-nec", ARG_BOOL}, + {"$8", "proxy1.0", ARG_STRING}, + {"$9", "tftp-blksize", ARG_STRING}, + {"$A", "mail-from", ARG_STRING}, + {"$B", "mail-rcpt", ARG_STRING}, + {"$C", "ftp-pret", ARG_BOOL}, + {"$D", "proto", ARG_STRING}, + {"$E", "proto-redir", ARG_STRING}, + {"$F", "resolve", ARG_STRING}, + {"$G", "delegation", ARG_STRING}, + {"$H", "mail-auth", ARG_STRING}, + {"$I", "post303", ARG_BOOL}, + {"$J", "metalink", ARG_BOOL}, + {"$6", "sasl-authzid", ARG_STRING}, + {"$K", "sasl-ir", ARG_BOOL }, + {"$L", "test-event", ARG_BOOL}, + {"$M", "unix-socket", ARG_FILENAME}, + {"$N", "path-as-is", ARG_BOOL}, + {"$O", "socks5-gssapi-service", ARG_STRING}, + /* 'socks5-gssapi-service' merged with'proxy-service-name' and + deprecated since 7.49.0 */ + {"$O", "proxy-service-name", ARG_STRING}, + {"$P", "service-name", ARG_STRING}, + {"$Q", "proto-default", ARG_STRING}, + {"$R", "expect100-timeout", ARG_STRING}, + {"$S", "tftp-no-options", ARG_BOOL}, + {"$U", "connect-to", ARG_STRING}, + {"$W", "abstract-unix-socket", ARG_FILENAME}, + {"$X", "tls-max", ARG_STRING}, + {"$Y", "suppress-connect-headers", ARG_BOOL}, + {"$Z", "compressed-ssh", ARG_BOOL}, + {"$~", "happy-eyeballs-timeout-ms", ARG_STRING}, + {"$!", "retry-all-errors", ARG_BOOL}, + {"0", "http1.0", ARG_NONE}, + {"01", "http1.1", ARG_NONE}, + {"02", "http2", ARG_NONE}, + {"03", "http2-prior-knowledge", ARG_NONE}, + {"04", "http3", ARG_NONE}, + {"09", "http0.9", ARG_BOOL}, + {"1", "tlsv1", ARG_NONE}, + {"10", "tlsv1.0", ARG_NONE}, + {"11", "tlsv1.1", ARG_NONE}, + {"12", "tlsv1.2", ARG_NONE}, + {"13", "tlsv1.3", ARG_NONE}, + {"1A", "tls13-ciphers", ARG_STRING}, + {"1B", "proxy-tls13-ciphers", ARG_STRING}, + {"2", "sslv2", ARG_NONE}, + {"3", "sslv3", ARG_NONE}, + {"4", "ipv4", ARG_NONE}, + {"6", "ipv6", ARG_NONE}, + {"a", "append", ARG_BOOL}, + {"A", "user-agent", ARG_STRING}, + {"b", "cookie", ARG_STRING}, + {"ba", "alt-svc", ARG_STRING}, + {"bb", "hsts", ARG_STRING}, + {"B", "use-ascii", ARG_BOOL}, + {"c", "cookie-jar", ARG_STRING}, + {"C", "continue-at", ARG_STRING}, + {"d", "data", ARG_STRING}, + {"dr", "data-raw", ARG_STRING}, + {"da", "data-ascii", ARG_STRING}, + {"db", "data-binary", ARG_STRING}, + {"de", "data-urlencode", ARG_STRING}, + {"df", "json", ARG_STRING}, + {"D", "dump-header", ARG_FILENAME}, + {"e", "referer", ARG_STRING}, + {"E", "cert", ARG_FILENAME}, + {"Ea", "cacert", ARG_FILENAME}, + {"Eb", "cert-type", ARG_STRING}, + {"Ec", "key", ARG_FILENAME}, + {"Ed", "key-type", ARG_STRING}, + {"Ee", "pass", ARG_STRING}, + {"Ef", "engine", ARG_STRING}, + {"Eg", "capath", ARG_FILENAME}, + {"Eh", "pubkey", ARG_STRING}, + {"Ei", "hostpubmd5", ARG_STRING}, + {"EF", "hostpubsha256", ARG_STRING}, + {"Ej", "crlfile", ARG_FILENAME}, + {"Ek", "tlsuser", ARG_STRING}, + {"El", "tlspassword", ARG_STRING}, + {"Em", "tlsauthtype", ARG_STRING}, + {"En", "ssl-allow-beast", ARG_BOOL}, + {"Eo", "ssl-auto-client-cert", ARG_BOOL}, + {"EO", "proxy-ssl-auto-client-cert", ARG_BOOL}, + {"Ep", "pinnedpubkey", ARG_STRING}, + {"EP", "proxy-pinnedpubkey", ARG_STRING}, + {"Eq", "cert-status", ARG_BOOL}, + {"EQ", "doh-cert-status", ARG_BOOL}, + {"Er", "false-start", ARG_BOOL}, + {"Es", "ssl-no-revoke", ARG_BOOL}, + {"ES", "ssl-revoke-best-effort", ARG_BOOL}, + {"Et", "tcp-fastopen", ARG_BOOL}, + {"Eu", "proxy-tlsuser", ARG_STRING}, + {"Ev", "proxy-tlspassword", ARG_STRING}, + {"Ew", "proxy-tlsauthtype", ARG_STRING}, + {"Ex", "proxy-cert", ARG_FILENAME}, + {"Ey", "proxy-cert-type", ARG_STRING}, + {"Ez", "proxy-key", ARG_FILENAME}, + {"E0", "proxy-key-type", ARG_STRING}, + {"E1", "proxy-pass", ARG_STRING}, + {"E2", "proxy-ciphers", ARG_STRING}, + {"E3", "proxy-crlfile", ARG_FILENAME}, + {"E4", "proxy-ssl-allow-beast", ARG_BOOL}, + {"E5", "login-options", ARG_STRING}, + {"E6", "proxy-cacert", ARG_FILENAME}, + {"E7", "proxy-capath", ARG_FILENAME}, + {"E8", "proxy-insecure", ARG_BOOL}, + {"E9", "proxy-tlsv1", ARG_NONE}, + {"EA", "socks5-basic", ARG_BOOL}, + {"EB", "socks5-gssapi", ARG_BOOL}, + {"EC", "etag-save", ARG_FILENAME}, + {"ED", "etag-compare", ARG_FILENAME}, + {"EE", "curves", ARG_STRING}, + {"f", "fail", ARG_BOOL}, + {"fa", "fail-early", ARG_BOOL}, + {"fb", "styled-output", ARG_BOOL}, + {"fc", "mail-rcpt-allowfails", ARG_BOOL}, + {"fd", "fail-with-body", ARG_BOOL}, + {"fe", "remove-on-error", ARG_BOOL}, + {"F", "form", ARG_STRING}, + {"Fs", "form-string", ARG_STRING}, + {"g", "globoff", ARG_BOOL}, + {"G", "get", ARG_NONE}, + {"Ga", "request-target", ARG_STRING}, + {"h", "help", ARG_BOOL}, + {"H", "header", ARG_STRING}, + {"Hp", "proxy-header", ARG_STRING}, + {"i", "include", ARG_BOOL}, + {"I", "head", ARG_BOOL}, + {"j", "junk-session-cookies", ARG_BOOL}, + {"J", "remote-header-name", ARG_BOOL}, + {"k", "insecure", ARG_BOOL}, + {"kd", "doh-insecure", ARG_BOOL}, + {"K", "config", ARG_FILENAME}, + {"l", "list-only", ARG_BOOL}, + {"L", "location", ARG_BOOL}, + {"Lt", "location-trusted", ARG_BOOL}, + {"m", "max-time", ARG_STRING}, + {"M", "manual", ARG_BOOL}, + {"n", "netrc", ARG_BOOL}, + {"no", "netrc-optional", ARG_BOOL}, + {"ne", "netrc-file", ARG_FILENAME}, + {"N", "buffer", ARG_BOOL}, + /* 'buffer' listed as --no-buffer in the help */ + {"o", "output", ARG_FILENAME}, + {"O", "remote-name", ARG_BOOL}, + {"Oa", "remote-name-all", ARG_BOOL}, + {"Ob", "output-dir", ARG_STRING}, + {"Oc", "clobber", ARG_BOOL}, + {"p", "proxytunnel", ARG_BOOL}, + {"P", "ftp-port", ARG_STRING}, + {"q", "disable", ARG_BOOL}, + {"Q", "quote", ARG_STRING}, + {"r", "range", ARG_STRING}, + {"R", "remote-time", ARG_BOOL}, + {"s", "silent", ARG_BOOL}, + {"S", "show-error", ARG_BOOL}, + {"t", "telnet-option", ARG_STRING}, + {"T", "upload-file", ARG_FILENAME}, + {"u", "user", ARG_STRING}, + {"U", "proxy-user", ARG_STRING}, + {"v", "verbose", ARG_BOOL}, + {"V", "version", ARG_BOOL}, + {"w", "write-out", ARG_STRING}, + {"x", "proxy", ARG_STRING}, + {"xa", "preproxy", ARG_STRING}, + {"X", "request", ARG_STRING}, + {"Y", "speed-limit", ARG_STRING}, + {"y", "speed-time", ARG_STRING}, + {"z", "time-cond", ARG_STRING}, + {"Z", "parallel", ARG_BOOL}, + {"Zb", "parallel-max", ARG_STRING}, + {"Zc", "parallel-immediate", ARG_BOOL}, + {"#", "progress-bar", ARG_BOOL}, + {"#m", "progress-meter", ARG_BOOL}, + {":", "next", ARG_NONE}, +}; + +/* Split the argument of -E to 'certname' and 'passphrase' separated by colon. + * We allow ':' and '\' to be escaped by '\' so that we can use certificate + * nicknames containing ':'. See <https://sourceforge.net/p/curl/bugs/1196/> + * for details. */ +#ifndef UNITTESTS +static +#endif +void parse_cert_parameter(const char *cert_parameter, + char **certname, + char **passphrase) +{ + size_t param_length = strlen(cert_parameter); + size_t span; + const char *param_place = NULL; + char *certname_place = NULL; + *certname = NULL; + *passphrase = NULL; + + /* most trivial assumption: cert_parameter is empty */ + if(param_length == 0) + return; + + /* next less trivial: cert_parameter starts 'pkcs11:' and thus + * looks like a RFC7512 PKCS#11 URI which can be used as-is. + * Also if cert_parameter contains no colon nor backslash, this + * means no passphrase was given and no characters escaped */ + if(curl_strnequal(cert_parameter, "pkcs11:", 7) || + !strpbrk(cert_parameter, ":\\")) { + *certname = strdup(cert_parameter); + return; + } + /* deal with escaped chars; find unescaped colon if it exists */ + certname_place = malloc(param_length + 1); + if(!certname_place) + return; + + *certname = certname_place; + param_place = cert_parameter; + while(*param_place) { + span = strcspn(param_place, ":\\"); + strncpy(certname_place, param_place, span); + param_place += span; + certname_place += span; + /* we just ate all the non-special chars. now we're on either a special + * char or the end of the string. */ + switch(*param_place) { + case '\0': + break; + case '\\': + param_place++; + switch(*param_place) { + case '\0': + *certname_place++ = '\\'; + break; + case '\\': + *certname_place++ = '\\'; + param_place++; + break; + case ':': + *certname_place++ = ':'; + param_place++; + break; + default: + *certname_place++ = '\\'; + *certname_place++ = *param_place; + param_place++; + break; + } + break; + case ':': + /* Since we live in a world of weirdness and confusion, the win32 + dudes can use : when using drive letters and thus c:\file:password + needs to work. In order not to break compatibility, we still use : as + separator, but we try to detect when it is used for a file name! On + windows. */ +#ifdef WIN32 + if((param_place == &cert_parameter[1]) && + (cert_parameter[2] == '\\' || cert_parameter[2] == '/') && + (ISALPHA(cert_parameter[0])) ) { + /* colon in the second column, followed by a backslash, and the + first character is an alphabetic letter: + + this is a drive letter colon */ + *certname_place++ = ':'; + param_place++; + break; + } +#endif + /* escaped colons and Windows drive letter colons were handled + * above; if we're still here, this is a separating colon */ + param_place++; + if(*param_place) { + *passphrase = strdup(param_place); + } + goto done; + } + } +done: + *certname_place = '\0'; +} + +/* Replace (in-place) '%20' by '+' according to RFC1866 */ +static size_t replace_url_encoded_space_by_plus(char *url) +{ + size_t orig_len = strlen(url); + size_t orig_index = 0; + size_t new_index = 0; + + while(orig_index < orig_len) { + if((url[orig_index] == '%') && + (url[orig_index + 1] == '2') && + (url[orig_index + 2] == '0')) { + url[new_index] = '+'; + orig_index += 3; + } + else{ + if(new_index != orig_index) { + url[new_index] = url[orig_index]; + } + orig_index++; + } + new_index++; + } + + url[new_index] = 0; /* terminate string */ + + return new_index; /* new size */ +} + +static void +GetFileAndPassword(char *nextarg, char **file, char **password) +{ + char *certname, *passphrase; + parse_cert_parameter(nextarg, &certname, &passphrase); + Curl_safefree(*file); + *file = certname; + if(passphrase) { + Curl_safefree(*password); + *password = passphrase; + } +} + +/* Get a size parameter for '--limit-rate' or '--max-filesize'. + * We support a 'G', 'M' or 'K' suffix too. + */ +static ParameterError GetSizeParameter(struct GlobalConfig *global, + const char *arg, + const char *which, + curl_off_t *value_out) +{ + char *unit; + curl_off_t value; + + if(curlx_strtoofft(arg, &unit, 0, &value)) { + warnf(global, "invalid number specified for %s\n", which); + return PARAM_BAD_USE; + } + + if(!*unit) + unit = (char *)"b"; + else if(strlen(unit) > 1) + unit = (char *)"w"; /* unsupported */ + + switch(*unit) { + case 'G': + case 'g': + if(value > (CURL_OFF_T_MAX / (1024*1024*1024))) + return PARAM_NUMBER_TOO_LARGE; + value *= 1024*1024*1024; + break; + case 'M': + case 'm': + if(value > (CURL_OFF_T_MAX / (1024*1024))) + return PARAM_NUMBER_TOO_LARGE; + value *= 1024*1024; + break; + case 'K': + case 'k': + if(value > (CURL_OFF_T_MAX / 1024)) + return PARAM_NUMBER_TOO_LARGE; + value *= 1024; + break; + case 'b': + case 'B': + /* for plain bytes, leave as-is */ + break; + default: + warnf(global, "unsupported %s unit. Use G, M, K or B!\n", which); + return PARAM_BAD_USE; + } + *value_out = value; + return PARAM_OK; +} + +#ifdef HAVE_WRITABLE_ARGV +static void cleanarg(argv_item_t str) +{ + /* now that GetStr has copied the contents of nextarg, wipe the next + * argument out so that the username:password isn't displayed in the + * system process list */ + if(str) { + size_t len = strlen(str); + memset(str, ' ', len); + } +} +#else +#define cleanarg(x) +#endif + +ParameterError getparameter(const char *flag, /* f or -long-flag */ + char *nextarg, /* NULL if unset */ + bool *usedarg, /* set to TRUE if the arg + has been used */ + struct GlobalConfig *global, + struct OperationConfig *config) +{ + char letter; + char subletter = '\0'; /* subletters can only occur on long options */ + int rc; + const char *parse = NULL; + unsigned int j; + time_t now; + int hit = -1; + bool longopt = FALSE; + bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ + ParameterError err; + bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled + by using --OPTION or --no-OPTION */ +#ifdef HAVE_WRITABLE_ARGV + argv_item_t clearthis = NULL; +#endif + *usedarg = FALSE; /* default is that we don't use the arg */ + + if(('-' != flag[0]) || ('-' == flag[1])) { + /* this should be a long name */ + const char *word = ('-' == flag[0]) ? flag + 2 : flag; + size_t fnam = strlen(word); + int numhits = 0; + bool noflagged = FALSE; + + if(!strncmp(word, "no-", 3)) { + /* disable this option but ignore the "no-" part when looking for it */ + word += 3; + toggle = FALSE; + noflagged = TRUE; + } + + for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { + if(curl_strnequal(aliases[j].lname, word, fnam)) { + longopt = TRUE; + numhits++; + if(curl_strequal(aliases[j].lname, word)) { + parse = aliases[j].letter; + hit = j; + numhits = 1; /* a single unique hit */ + break; + } + parse = aliases[j].letter; + hit = j; + } + } + if(numhits > 1) { + /* this is at least the second match! */ + return PARAM_OPTION_AMBIGUOUS; + } + if(hit < 0) { + return PARAM_OPTION_UNKNOWN; + } + if(noflagged && (aliases[hit].desc != ARG_BOOL)) + /* --no- prefixed an option that isn't boolean! */ + return PARAM_NO_NOT_BOOLEAN; + } + else { + flag++; /* prefixed with one dash, pass it */ + hit = -1; + parse = flag; + } + + do { + /* we can loop here if we have multiple single-letters */ + + if(!longopt) { + letter = (char)*parse; + subletter = '\0'; + } + else { + letter = parse[0]; + subletter = parse[1]; + } + + if(hit < 0) { + for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { + if(letter == aliases[j].letter[0]) { + hit = j; + break; + } + } + if(hit < 0) { + return PARAM_OPTION_UNKNOWN; + } + } + + if(aliases[hit].desc >= ARG_STRING) { + /* this option requires an extra parameter */ + if(!longopt && parse[1]) { + nextarg = (char *)&parse[1]; /* this is the actual extra parameter */ +#ifdef HAVE_WRITABLE_ARGV + clearthis = nextarg; +#endif + singleopt = TRUE; /* don't loop anymore after this */ + } + else if(!nextarg) + return PARAM_REQUIRES_PARAMETER; + else + *usedarg = TRUE; /* mark it as used */ + + if((aliases[hit].desc == ARG_FILENAME) && + (nextarg[0] == '-') && nextarg[1]) { + /* if the file name looks like a command line option */ + warnf(global, "The file name argument '%s' looks like a flag.\n", + nextarg); + } + } + else if((aliases[hit].desc == ARG_NONE) && !toggle) + return PARAM_NO_PREFIX; + + switch(letter) { + case '*': /* options without a short option */ + switch(subletter) { + case '4': /* --dns-ipv4-addr */ + if(!curlinfo->ares_num) /* c-ares is needed for this */ + return PARAM_LIBCURL_DOESNT_SUPPORT; + /* addr in dot notation */ + GetStr(&config->dns_ipv4_addr, nextarg); + break; + case '6': /* --dns-ipv6-addr */ + if(!curlinfo->ares_num) /* c-ares is needed for this */ + return PARAM_LIBCURL_DOESNT_SUPPORT; + /* addr in dot notation */ + GetStr(&config->dns_ipv6_addr, nextarg); + break; + case 'a': /* random-file */ + break; + case 'b': /* egd-file */ + break; + case 'B': /* OAuth 2.0 bearer token */ + GetStr(&config->oauth_bearer, nextarg); + cleanarg(clearthis); + config->authtype |= CURLAUTH_BEARER; + break; + case 'c': /* connect-timeout */ + err = str2udouble(&config->connecttimeout, nextarg, + LONG_MAX/1000); + if(err) + return err; + break; + case 'C': /* doh-url */ + GetStr(&config->doh_url, nextarg); + if(config->doh_url && !config->doh_url[0]) + /* if given a blank string, we make it NULL again */ + Curl_safefree(config->doh_url); + break; + case 'd': /* ciphers */ + GetStr(&config->cipher_list, nextarg); + break; + case 'D': /* --dns-interface */ + if(!curlinfo->ares_num) /* c-ares is needed for this */ + return PARAM_LIBCURL_DOESNT_SUPPORT; + /* interface name */ + GetStr(&config->dns_interface, nextarg); + break; + case 'e': /* --disable-epsv */ + config->disable_epsv = toggle; + break; + case 'f': /* --disallow-username-in-url */ + config->disallow_username_in_url = toggle; + break; + case 'E': /* --epsv */ + config->disable_epsv = (!toggle)?TRUE:FALSE; + break; + case 'F': /* --dns-servers */ + if(!curlinfo->ares_num) /* c-ares is needed for this */ + return PARAM_LIBCURL_DOESNT_SUPPORT; + /* IP addrs of DNS servers */ + GetStr(&config->dns_servers, nextarg); + break; + case 'g': /* --trace */ + GetStr(&global->trace_dump, nextarg); + if(global->tracetype && (global->tracetype != TRACE_BIN)) + warnf(global, "--trace overrides an earlier trace/verbose option\n"); + global->tracetype = TRACE_BIN; + break; + case 'G': /* --npn */ + config->nonpn = (!toggle)?TRUE:FALSE; + break; + case 'h': /* --trace-ascii */ + GetStr(&global->trace_dump, nextarg); + if(global->tracetype && (global->tracetype != TRACE_ASCII)) + warnf(global, + "--trace-ascii overrides an earlier trace/verbose option\n"); + global->tracetype = TRACE_ASCII; + break; + case 'H': /* --alpn */ + config->noalpn = (!toggle)?TRUE:FALSE; + break; + case 'i': /* --limit-rate */ + { + curl_off_t value; + ParameterError pe = GetSizeParameter(global, nextarg, "rate", &value); + + if(pe != PARAM_OK) + return pe; + config->recvpersecond = value; + config->sendpersecond = value; + } + break; + case 'I': /* --rate (request rate) */ + { + /* support a few different suffixes, extract the suffix first, then + get the number and convert to per hour. + /s == per second + /m == per minute + /h == per hour (default) + /d == per day (24 hours) + */ + char *div = strchr(nextarg, '/'); + char number[26]; + long denominator; + long numerator = 60*60*1000; /* default per hour */ + size_t numlen = div ? (size_t)(div - nextarg) : strlen(nextarg); + if(numlen > sizeof(number)-1) + return PARAM_NUMBER_TOO_LARGE; + strncpy(number, nextarg, numlen); + number[numlen] = 0; + err = str2unum(&denominator, number); + if(err) + return err; + if(denominator < 1) + return PARAM_BAD_USE; + if(div) { + char unit = div[1]; + switch(unit) { + case 's': /* per second */ + numerator = 1000; + break; + case 'm': /* per minute */ + numerator = 60*1000; + break; + case 'h': /* per hour */ + break; + case 'd': /* per day */ + numerator = 24*60*60*1000; + break; + default: + errorf(global, "unsupported --rate unit\n"); + return PARAM_BAD_USE; + } + } + global->ms_per_transfer = numerator/denominator; + } + break; + + case 'j': /* --compressed */ + if(toggle && + !(curlinfo->features & (CURL_VERSION_LIBZ | + CURL_VERSION_BROTLI | CURL_VERSION_ZSTD))) + return PARAM_LIBCURL_DOESNT_SUPPORT; + config->encoding = toggle; + break; + + case 'J': /* --tr-encoding */ + config->tr_encoding = toggle; + break; + + case 'k': /* --digest */ + if(toggle) + config->authtype |= CURLAUTH_DIGEST; + else + config->authtype &= ~CURLAUTH_DIGEST; + break; + + case 'l': /* --negotiate */ + if(toggle) { + if(curlinfo->features & CURL_VERSION_SPNEGO) + config->authtype |= CURLAUTH_NEGOTIATE; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + else + config->authtype &= ~CURLAUTH_NEGOTIATE; + break; + + case 'm': /* --ntlm */ + if(toggle) { + if(curlinfo->features & CURL_VERSION_NTLM) + config->authtype |= CURLAUTH_NTLM; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + else + config->authtype &= ~CURLAUTH_NTLM; + break; + + case 'M': /* --ntlm-wb */ + if(toggle) { + if(curlinfo->features & CURL_VERSION_NTLM_WB) + config->authtype |= CURLAUTH_NTLM_WB; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + else + config->authtype &= ~CURLAUTH_NTLM_WB; + break; + + case 'n': /* --basic for completeness */ + if(toggle) + config->authtype |= CURLAUTH_BASIC; + else + config->authtype &= ~CURLAUTH_BASIC; + break; + + case 'o': /* --anyauth, let libcurl pick it */ + if(toggle) + config->authtype = CURLAUTH_ANY; + /* --no-anyauth simply doesn't touch it */ + break; + +#ifdef USE_WATT32 + case 'p': /* --wdebug */ + dbug_init(); + break; +#endif + case 'q': /* --ftp-create-dirs */ + config->ftp_create_dirs = toggle; + break; + + case 'r': /* --create-dirs */ + config->create_dirs = toggle; + break; + + case 'R': /* --create-file-mode */ + err = oct2nummax(&config->create_file_mode, nextarg, 0777); + if(err) + return err; + break; + + case 's': /* --max-redirs */ + /* specified max no of redirects (http(s)), this accepts -1 as a + special condition */ + err = str2num(&config->maxredirs, nextarg); + if(err) + return err; + if(config->maxredirs < -1) + return PARAM_BAD_NUMERIC; + break; + + case 't': /* --proxy-ntlm */ + if(curlinfo->features & CURL_VERSION_NTLM) + config->proxyntlm = toggle; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + + case 'u': /* --crlf */ + /* LF -> CRLF conversion? */ + config->crlf = toggle; + break; + + case 'V': /* --aws-sigv4 */ + config->authtype |= CURLAUTH_AWS_SIGV4; + GetStr(&config->aws_sigv4, nextarg); + break; + + case 'v': /* --stderr */ + if(strcmp(nextarg, "-")) { + FILE *newfile = fopen(nextarg, FOPEN_WRITETEXT); + if(!newfile) + warnf(global, "Failed to open %s!\n", nextarg); + else { + if(global->errors_fopened) + fclose(global->errors); + global->errors = newfile; + global->errors_fopened = TRUE; + } + } + else + global->errors = stdout; + break; + case 'w': /* --interface */ + /* interface */ + GetStr(&config->iface, nextarg); + break; + case 'x': /* --krb */ + /* kerberos level string */ + if(curlinfo->features & CURL_VERSION_SPNEGO) + GetStr(&config->krblevel, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'X': /* --haproxy-protocol */ + config->haproxy_protocol = toggle; + break; + case 'y': /* --max-filesize */ + { + curl_off_t value; + ParameterError pe = + GetSizeParameter(global, nextarg, "max-filesize", &value); + + if(pe != PARAM_OK) + return pe; + config->max_filesize = value; + } + break; + case 'z': /* --disable-eprt */ + config->disable_eprt = toggle; + break; + case 'Z': /* --eprt */ + config->disable_eprt = (!toggle)?TRUE:FALSE; + break; + case '~': /* --xattr */ + config->xattr = toggle; + break; + case '@': /* the URL! */ + { + struct getout *url; + + if(!config->url_get) + config->url_get = config->url_list; + + if(config->url_get) { + /* there's a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_get && (config->url_get->flags & GETOUT_URL)) + config->url_get = config->url_get->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_get) + /* existing node */ + url = config->url_get; + else + /* there was no free node, create one! */ + config->url_get = url = new_getout(config); + + if(!url) + return PARAM_NO_MEM; + + /* fill in the URL */ + GetStr(&url->url, nextarg); + url->flags |= GETOUT_URL; + } + } + break; + case '$': /* more options without a short option */ + switch(subletter) { + case 'a': /* --ssl */ + if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) + return PARAM_LIBCURL_DOESNT_SUPPORT; + config->ftp_ssl = toggle; + break; + case 'b': /* --ftp-pasv */ + Curl_safefree(config->ftpport); + break; + case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves + the name locally and passes on the resolved address */ + GetStr(&config->proxy, nextarg); + config->proxyver = CURLPROXY_SOCKS5; + break; + case 't': /* --socks4 specifies a socks4 proxy to use */ + GetStr(&config->proxy, nextarg); + config->proxyver = CURLPROXY_SOCKS4; + break; + case 'T': /* --socks4a specifies a socks4a proxy to use */ + GetStr(&config->proxy, nextarg); + config->proxyver = CURLPROXY_SOCKS4A; + break; + case '2': /* --socks5-hostname specifies a socks5 proxy and enables name + resolving with the proxy */ + GetStr(&config->proxy, nextarg); + config->proxyver = CURLPROXY_SOCKS5_HOSTNAME; + break; + case 'd': /* --tcp-nodelay option */ + config->tcp_nodelay = toggle; + break; + case 'e': /* --proxy-digest */ + config->proxydigest = toggle; + break; + case 'f': /* --proxy-basic */ + config->proxybasic = toggle; + break; + case 'g': /* --retry */ + err = str2unum(&config->req_retry, nextarg); + if(err) + return err; + break; + case 'V': /* --retry-connrefused */ + config->retry_connrefused = toggle; + break; + case 'h': /* --retry-delay */ + err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000); + if(err) + return err; + break; + case 'i': /* --retry-max-time */ + err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000); + if(err) + return err; + break; + case '!': /* --retry-all-errors */ + config->retry_all_errors = toggle; + break; + + case 'k': /* --proxy-negotiate */ + if(curlinfo->features & CURL_VERSION_SPNEGO) + config->proxynegotiate = toggle; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + + case 'l': /* --form-escape */ + config->mime_options &= ~CURLMIMEOPT_FORMESCAPE; + if(toggle) + config->mime_options |= CURLMIMEOPT_FORMESCAPE; + break; + + case 'm': /* --ftp-account */ + GetStr(&config->ftp_account, nextarg); + break; + case 'n': /* --proxy-anyauth */ + config->proxyanyauth = toggle; + break; + case 'o': /* --trace-time */ + global->tracetime = toggle; + break; + case 'p': /* --ignore-content-length */ + config->ignorecl = toggle; + break; + case 'q': /* --ftp-skip-pasv-ip */ + config->ftp_skip_ip = toggle; + break; + case 'r': /* --ftp-method (undocumented at this point) */ + config->ftp_filemethod = ftpfilemethod(config, nextarg); + break; + case 's': { /* --local-port */ + /* 16bit base 10 is 5 digits, but we allow 6 so that this catches + overflows, not just truncates */ + char lrange[7]=""; + char *p = nextarg; + while(ISDIGIT(*p)) + p++; + if(*p) { + /* if there's anything more than a plain decimal number */ + rc = sscanf(p, " - %6s", lrange); + *p = 0; /* null-terminate to make str2unum() work below */ + } + else + rc = 0; + + err = str2unum(&config->localport, nextarg); + if(err || (config->localport > 65535)) + return PARAM_BAD_USE; + if(!rc) + config->localportrange = 1; /* default number of ports to try */ + else { + err = str2unum(&config->localportrange, lrange); + if(err || (config->localportrange > 65535)) + return PARAM_BAD_USE; + config->localportrange -= (config->localport-1); + if(config->localportrange < 1) + return PARAM_BAD_USE; + } + break; + } + case 'u': /* --ftp-alternative-to-user */ + GetStr(&config->ftp_alternative_to_user, nextarg); + break; + case 'v': /* --ssl-reqd */ + if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) + return PARAM_LIBCURL_DOESNT_SUPPORT; + config->ftp_ssl_reqd = toggle; + break; + case 'w': /* --no-sessionid */ + config->disable_sessionid = (!toggle)?TRUE:FALSE; + break; + case 'x': /* --ftp-ssl-control */ + if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) + return PARAM_LIBCURL_DOESNT_SUPPORT; + config->ftp_ssl_control = toggle; + break; + case 'y': /* --ftp-ssl-ccc */ + config->ftp_ssl_ccc = toggle; + if(!config->ftp_ssl_ccc_mode) + config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; + break; + case 'j': /* --ftp-ssl-ccc-mode */ + config->ftp_ssl_ccc = TRUE; + config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); + break; + case 'z': /* --libcurl */ +#ifdef CURL_DISABLE_LIBCURL_OPTION + warnf(global, + "--libcurl option was disabled at build-time!\n"); + return PARAM_OPTION_UNKNOWN; +#else + GetStr(&global->libcurl, nextarg); + break; +#endif + case '#': /* --raw */ + config->raw = toggle; + break; + case '0': /* --post301 */ + config->post301 = toggle; + break; + case '1': /* --no-keepalive */ + config->nokeepalive = (!toggle)?TRUE:FALSE; + break; + case '3': /* --keepalive-time */ + err = str2unum(&config->alivetime, nextarg); + if(err) + return err; + break; + case '4': /* --post302 */ + config->post302 = toggle; + break; + case 'I': /* --post303 */ + config->post303 = toggle; + break; + case '5': /* --noproxy */ + /* This specifies the noproxy list */ + GetStr(&config->noproxy, nextarg); + break; + case '7': /* --socks5-gssapi-nec*/ + config->socks5_gssapi_nec = toggle; + break; + case '8': /* --proxy1.0 */ + /* http 1.0 proxy */ + GetStr(&config->proxy, nextarg); + config->proxyver = CURLPROXY_HTTP_1_0; + break; + case '9': /* --tftp-blksize */ + err = str2unum(&config->tftp_blksize, nextarg); + if(err) + return err; + break; + case 'A': /* --mail-from */ + GetStr(&config->mail_from, nextarg); + break; + case 'B': /* --mail-rcpt */ + /* append receiver to a list */ + err = add2list(&config->mail_rcpt, nextarg); + if(err) + return err; + break; + case 'C': /* --ftp-pret */ + config->ftp_pret = toggle; + break; + case 'D': /* --proto */ + config->proto_present = TRUE; + err = proto2num(config, (unsigned int)CURLPROTO_ALL, + &config->proto_str, nextarg); + if(err) + return err; + break; + case 'E': /* --proto-redir */ + config->proto_redir_present = TRUE; + if(proto2num(config, CURLPROTO_HTTP|CURLPROTO_HTTPS| + CURLPROTO_FTP|CURLPROTO_FTPS, + &config->proto_redir_str, nextarg)) + return PARAM_BAD_USE; + break; + case 'F': /* --resolve */ + err = add2list(&config->resolve, nextarg); + if(err) + return err; + break; + case 'G': /* --delegation LEVEL */ + config->gssapi_delegation = delegation(config, nextarg); + break; + case 'H': /* --mail-auth */ + GetStr(&config->mail_auth, nextarg); + break; + case 'J': /* --metalink */ + errorf(global, "--metalink is disabled\n"); + return PARAM_BAD_USE; + case '6': /* --sasl-authzid */ + GetStr(&config->sasl_authzid, nextarg); + break; + case 'K': /* --sasl-ir */ + config->sasl_ir = toggle; + break; + case 'L': /* --test-event */ +#ifdef CURLDEBUG + global->test_event_based = toggle; +#else + warnf(global, "--test-event is ignored unless a debug build!\n"); +#endif + break; + case 'M': /* --unix-socket */ + config->abstract_unix_socket = FALSE; + GetStr(&config->unix_socket_path, nextarg); + break; + case 'N': /* --path-as-is */ + config->path_as_is = toggle; + break; + case 'O': /* --proxy-service-name */ + GetStr(&config->proxy_service_name, nextarg); + break; + case 'P': /* --service-name */ + GetStr(&config->service_name, nextarg); + break; + case 'Q': /* --proto-default */ + GetStr(&config->proto_default, nextarg); + err = check_protocol(config->proto_default); + if(err) + return err; + break; + case 'R': /* --expect100-timeout */ + err = str2udouble(&config->expect100timeout, nextarg, LONG_MAX/1000); + if(err) + return err; + break; + case 'S': /* --tftp-no-options */ + config->tftp_no_options = toggle; + break; + case 'U': /* --connect-to */ + err = add2list(&config->connect_to, nextarg); + if(err) + return err; + break; + case 'W': /* --abstract-unix-socket */ + config->abstract_unix_socket = TRUE; + GetStr(&config->unix_socket_path, nextarg); + break; + case 'X': /* --tls-max */ + err = str2tls_max(&config->ssl_version_max, nextarg); + if(err) + return err; + break; + case 'Y': /* --suppress-connect-headers */ + config->suppress_connect_headers = toggle; + break; + case 'Z': /* --compressed-ssh */ + config->ssh_compression = toggle; + break; + case '~': /* --happy-eyeballs-timeout-ms */ + err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg); + if(err) + return err; + /* 0 is a valid value for this timeout */ + break; + } + break; + case '#': + switch(subletter) { + case 'm': /* --progress-meter */ + global->noprogress = !toggle; + break; + default: /* --progress-bar */ + global->progressmode = + toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS; + break; + } + break; + case ':': /* --next */ + return PARAM_NEXT_OPERATION; + case '0': /* --http* options */ + switch(subletter) { + case '\0': + /* HTTP version 1.0 */ + config->httpversion = CURL_HTTP_VERSION_1_0; + break; + case '1': + /* HTTP version 1.1 */ + config->httpversion = CURL_HTTP_VERSION_1_1; + break; + case '2': + /* HTTP version 2.0 */ + config->httpversion = CURL_HTTP_VERSION_2_0; + break; + case '3': /* --http2-prior-knowledge */ + /* HTTP version 2.0 over clean TCP*/ + config->httpversion = CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE; + break; + case '4': /* --http3 */ + /* HTTP version 3 go over QUIC - at once */ + if(curlinfo->features & CURL_VERSION_HTTP3) + config->httpversion = CURL_HTTP_VERSION_3; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case '9': + /* Allow HTTP/0.9 responses! */ + config->http09_allowed = toggle; + break; + } + break; + case '1': /* --tlsv1* options */ + switch(subletter) { + case '\0': + /* TLS version 1.x */ + config->ssl_version = CURL_SSLVERSION_TLSv1; + break; + case '0': + /* TLS version 1.0 */ + config->ssl_version = CURL_SSLVERSION_TLSv1_0; + break; + case '1': + /* TLS version 1.1 */ + config->ssl_version = CURL_SSLVERSION_TLSv1_1; + break; + case '2': + /* TLS version 1.2 */ + config->ssl_version = CURL_SSLVERSION_TLSv1_2; + break; + case '3': + /* TLS version 1.3 */ + config->ssl_version = CURL_SSLVERSION_TLSv1_3; + break; + case 'A': /* --tls13-ciphers */ + GetStr(&config->cipher13_list, nextarg); + break; + case 'B': /* --proxy-tls13-ciphers */ + GetStr(&config->proxy_cipher13_list, nextarg); + break; + } + break; + case '2': + /* SSL version 2 */ + warnf(global, "Ignores instruction to use SSLv2\n"); + break; + case '3': + /* SSL version 3 */ + warnf(global, "Ignores instruction to use SSLv3\n"); + break; + case '4': + /* IPv4 */ + config->ip_version = CURL_IPRESOLVE_V4; + break; + case '6': + /* IPv6 */ + config->ip_version = CURL_IPRESOLVE_V6; + break; + case 'a': + /* This makes the FTP sessions use APPE instead of STOR */ + config->ftp_append = toggle; + break; + case 'A': + /* This specifies the User-Agent name */ + GetStr(&config->useragent, nextarg); + break; + case 'b': + switch(subletter) { + case 'a': /* --alt-svc */ + if(curlinfo->features & CURL_VERSION_ALTSVC) + GetStr(&config->altsvc, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'b': /* --hsts */ + if(curlinfo->features & CURL_VERSION_HSTS) + GetStr(&config->hsts, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + default: /* --cookie string coming up: */ + if(nextarg[0] == '@') { + nextarg++; + } + else if(strchr(nextarg, '=')) { + /* A cookie string must have a =-letter */ + err = add2list(&config->cookies, nextarg); + if(err) + return err; + break; + } + /* We have a cookie file to read from! */ + err = add2list(&config->cookiefiles, nextarg); + if(err) + return err; + } + break; + case 'B': + /* use ASCII/text when transferring */ + config->use_ascii = toggle; + break; + case 'c': + /* get the file name to dump all cookies in */ + GetStr(&config->cookiejar, nextarg); + break; + case 'C': + /* This makes us continue an ftp transfer at given position */ + if(strcmp(nextarg, "-")) { + err = str2offset(&config->resume_from, nextarg); + if(err) + return err; + config->resume_from_current = FALSE; + } + else { + config->resume_from_current = TRUE; + config->resume_from = 0; + } + config->use_resume = TRUE; + break; + case 'd': + /* postfield data */ + { + char *postdata = NULL; + FILE *file; + size_t size = 0; + bool raw_mode = (subletter == 'r'); + + if(subletter == 'e') { /* --data-urlencode */ + /* [name]=[content], we encode the content part only + * [name]@[file name] + * + * Case 2: we first load the file using that name and then encode + * the content. + */ + const char *p = strchr(nextarg, '='); + size_t nlen; + char is_file; + if(!p) + /* there was no '=' letter, check for a '@' instead */ + p = strchr(nextarg, '@'); + if(p) { + nlen = p - nextarg; /* length of the name part */ + is_file = *p++; /* pass the separator */ + } + else { + /* neither @ nor =, so no name and it isn't a file */ + nlen = is_file = 0; + p = nextarg; + } + if('@' == is_file) { + /* a '@' letter, it means that a file name or - (stdin) follows */ + if(!strcmp("-", p)) { + file = stdin; + set_binmode(stdin); + } + else { + file = fopen(p, "rb"); + if(!file) + warnf(global, + "Couldn't read data from file \"%s\", this makes " + "an empty POST.\n", nextarg); + } + + err = file2memory(&postdata, &size, file); + + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + } + else { + GetStr(&postdata, p); + if(postdata) + size = strlen(postdata); + } + + if(!postdata) { + /* no data from the file, point to a zero byte string to make this + get sent as a POST anyway */ + postdata = strdup(""); + if(!postdata) + return PARAM_NO_MEM; + size = 0; + } + else { + char *enc = curl_easy_escape(NULL, postdata, (int)size); + Curl_safefree(postdata); /* no matter if it worked or not */ + if(enc) { + /* replace (in-place) '%20' by '+' according to RFC1866 */ + size_t enclen = replace_url_encoded_space_by_plus(enc); + /* now make a string with the name from above and append the + encoded string */ + size_t outlen = nlen + enclen + 2; + char *n = malloc(outlen); + if(!n) { + curl_free(enc); + return PARAM_NO_MEM; + } + if(nlen > 0) { /* only append '=' if we have a name */ + msnprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc); + size = outlen-1; + } + else { + strcpy(n, enc); + size = outlen-2; /* since no '=' was inserted */ + } + curl_free(enc); + postdata = n; + } + else + return PARAM_NO_MEM; + } + } + else if('@' == *nextarg && !raw_mode) { + /* the data begins with a '@' letter, it means that a file name + or - (stdin) follows */ + nextarg++; /* pass the @ */ + + if(!strcmp("-", nextarg)) { + file = stdin; + if(subletter == 'b') /* forced data-binary */ + set_binmode(stdin); + } + else { + file = fopen(nextarg, "rb"); + if(!file) + warnf(global, "Couldn't read data from file \"%s\", this makes " + "an empty POST.\n", nextarg); + } + + if((subletter == 'b') || /* --data-binary */ + (subletter == 'f') /* --json */) + /* forced binary */ + err = file2memory(&postdata, &size, file); + else { + err = file2string(&postdata, file); + if(postdata) + size = strlen(postdata); + } + + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + + if(!postdata) { + /* no data from the file, point to a zero byte string to make this + get sent as a POST anyway */ + postdata = strdup(""); + if(!postdata) + return PARAM_NO_MEM; + } + } + else { + GetStr(&postdata, nextarg); + if(postdata) + size = strlen(postdata); + } + if(subletter == 'f') + config->jsoned = TRUE; + + if(config->postfields) { + /* we already have a string, we append this one with a separating + &-letter */ + char *oldpost = config->postfields; + curl_off_t oldlen = config->postfieldsize; + curl_off_t newlen = oldlen + curlx_uztoso(size) + 2; + config->postfields = malloc((size_t)newlen); + if(!config->postfields) { + Curl_safefree(oldpost); + Curl_safefree(postdata); + return PARAM_NO_MEM; + } + memcpy(config->postfields, oldpost, (size_t)oldlen); + if(subletter != 'f') { + /* skip this treatment for --json */ + /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */ + config->postfields[oldlen] = '\x26'; + memcpy(&config->postfields[oldlen + 1], postdata, size); + config->postfields[oldlen + 1 + size] = '\0'; + config->postfieldsize += size + 1; + } + else { + memcpy(&config->postfields[oldlen], postdata, size); + config->postfields[oldlen + size] = '\0'; + config->postfieldsize += size; + } + Curl_safefree(oldpost); + Curl_safefree(postdata); + } + else { + config->postfields = postdata; + config->postfieldsize = curlx_uztoso(size); + } + } + /* + We can't set the request type here, as this data might be used in + a simple GET if -G is used. Already or soon. + + if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) { + Curl_safefree(postdata); + return PARAM_BAD_USE; + } + */ + break; + case 'D': + /* dump-header to given file name */ + GetStr(&config->headerfile, nextarg); + break; + case 'e': + { + char *ptr = strstr(nextarg, ";auto"); + if(ptr) { + /* Automatic referer requested, this may be combined with a + set initial one */ + config->autoreferer = TRUE; + *ptr = 0; /* null-terminate here */ + } + else + config->autoreferer = FALSE; + ptr = *nextarg ? nextarg : NULL; + GetStr(&config->referer, ptr); + } + break; + case 'E': + switch(subletter) { + case '\0': /* certificate file */ + cleanarg(clearthis); + GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); + break; + case 'a': /* CA info PEM file */ + GetStr(&config->cacert, nextarg); + break; + case 'b': /* cert file type */ + GetStr(&config->cert_type, nextarg); + break; + case 'c': /* private key file */ + GetStr(&config->key, nextarg); + break; + case 'd': /* private key file type */ + GetStr(&config->key_type, nextarg); + break; + case 'e': /* private key passphrase */ + GetStr(&config->key_passwd, nextarg); + cleanarg(clearthis); + break; + case 'f': /* crypto engine */ + GetStr(&config->engine, nextarg); + if(config->engine && curl_strequal(config->engine, "list")) + return PARAM_ENGINES_REQUESTED; + break; + case 'g': /* CA cert directory */ + GetStr(&config->capath, nextarg); + break; + case 'h': /* --pubkey public key file */ + GetStr(&config->pubkey, nextarg); + break; + case 'i': /* --hostpubmd5 md5 of the host public key */ + GetStr(&config->hostpubmd5, nextarg); + if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) + return PARAM_BAD_USE; + break; + case 'F': /* --hostpubsha256 sha256 of the host public key */ + GetStr(&config->hostpubsha256, nextarg); + break; + case 'j': /* CRL file */ + GetStr(&config->crlfile, nextarg); + break; + case 'k': /* TLS username */ + if(!(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)) { + cleanarg(clearthis); + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + GetStr(&config->tls_username, nextarg); + cleanarg(clearthis); + break; + case 'l': /* TLS password */ + if(!(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)) { + cleanarg(clearthis); + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + GetStr(&config->tls_password, nextarg); + cleanarg(clearthis); + break; + case 'm': /* TLS authentication type */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + GetStr(&config->tls_authtype, nextarg); + if(!curl_strequal(config->tls_authtype, "SRP")) + return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ + } + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'n': /* no empty SSL fragments, --ssl-allow-beast */ + if(curlinfo->features & CURL_VERSION_SSL) + config->ssl_allow_beast = toggle; + break; + + case 'o': /* --ssl-auto-client-cert */ + if(curlinfo->features & CURL_VERSION_SSL) + config->ssl_auto_client_cert = toggle; + break; + + case 'O': /* --proxy-ssl-auto-client-cert */ + if(curlinfo->features & CURL_VERSION_SSL) + config->proxy_ssl_auto_client_cert = toggle; + break; + + case 'p': /* Pinned public key DER file */ + GetStr(&config->pinnedpubkey, nextarg); + break; + + case 'P': /* proxy pinned public key */ + GetStr(&config->proxy_pinnedpubkey, nextarg); + break; + + case 'q': /* --cert-status */ + config->verifystatus = TRUE; + break; + + case 'Q': /* --doh-cert-status */ + config->doh_verifystatus = TRUE; + break; + + case 'r': /* --false-start */ + config->falsestart = TRUE; + break; + + case 's': /* --ssl-no-revoke */ + if(curlinfo->features & CURL_VERSION_SSL) + config->ssl_no_revoke = TRUE; + break; + + case 'S': /* --ssl-revoke-best-effort */ + if(curlinfo->features & CURL_VERSION_SSL) + config->ssl_revoke_best_effort = TRUE; + break; + + case 't': /* --tcp-fastopen */ + config->tcp_fastopen = TRUE; + break; + + case 'u': /* TLS username for proxy */ + cleanarg(clearthis); + if(!(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)) { + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + GetStr(&config->proxy_tls_username, nextarg); + break; + + case 'v': /* TLS password for proxy */ + cleanarg(clearthis); + if(!(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)) { + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + GetStr(&config->proxy_tls_password, nextarg); + break; + + case 'w': /* TLS authentication type for proxy */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + GetStr(&config->proxy_tls_authtype, nextarg); + if(!curl_strequal(config->proxy_tls_authtype, "SRP")) + return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ + } + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + + case 'x': /* certificate file for proxy */ + cleanarg(clearthis); + GetFileAndPassword(nextarg, &config->proxy_cert, + &config->proxy_key_passwd); + break; + + case 'y': /* cert file type for proxy */ + GetStr(&config->proxy_cert_type, nextarg); + break; + + case 'z': /* private key file for proxy */ + GetStr(&config->proxy_key, nextarg); + break; + + case '0': /* private key file type for proxy */ + GetStr(&config->proxy_key_type, nextarg); + break; + + case '1': /* private key passphrase for proxy */ + GetStr(&config->proxy_key_passwd, nextarg); + cleanarg(clearthis); + break; + + case '2': /* ciphers for proxy */ + GetStr(&config->proxy_cipher_list, nextarg); + break; + + case '3': /* CRL file for proxy */ + GetStr(&config->proxy_crlfile, nextarg); + break; + + case '4': /* no empty SSL fragments for proxy */ + if(curlinfo->features & CURL_VERSION_SSL) + config->proxy_ssl_allow_beast = toggle; + break; + + case '5': /* --login-options */ + GetStr(&config->login_options, nextarg); + break; + + case '6': /* CA info PEM file for proxy */ + GetStr(&config->proxy_cacert, nextarg); + break; + + case '7': /* CA cert directory for proxy */ + GetStr(&config->proxy_capath, nextarg); + break; + + case '8': /* allow insecure SSL connects for proxy */ + config->proxy_insecure_ok = toggle; + break; + + case '9': /* --proxy-tlsv1 */ + /* TLS version 1 for proxy */ + config->proxy_ssl_version = CURL_SSLVERSION_TLSv1; + break; + + case 'A': + /* --socks5-basic */ + if(toggle) + config->socks5_auth |= CURLAUTH_BASIC; + else + config->socks5_auth &= ~CURLAUTH_BASIC; + break; + + case 'B': + /* --socks5-gssapi */ + if(toggle) + config->socks5_auth |= CURLAUTH_GSSAPI; + else + config->socks5_auth &= ~CURLAUTH_GSSAPI; + break; + + case 'C': + GetStr(&config->etag_save_file, nextarg); + break; + + case 'D': + GetStr(&config->etag_compare_file, nextarg); + break; + + case 'E': + GetStr(&config->ssl_ec_curves, nextarg); + break; + + default: /* unknown flag */ + return PARAM_OPTION_UNKNOWN; + } + break; + case 'f': + switch(subletter) { + case 'a': /* --fail-early */ + global->fail_early = toggle; + break; + case 'b': /* --styled-output */ + global->styled_output = toggle; + break; + case 'c': /* --mail-rcpt-allowfails */ + config->mail_rcpt_allowfails = toggle; + break; + case 'd': /* --fail-with-body */ + config->failwithbody = toggle; + break; + case 'e': /* --remove-on-error */ + config->rm_partial = toggle; + break; + default: /* --fail (hard on errors) */ + config->failonerror = toggle; + break; + } + if(config->failonerror && config->failwithbody) { + errorf(config->global, "You must select either --fail or " + "--fail-with-body, not both.\n"); + return PARAM_BAD_USE; + } + break; + case 'F': + /* "form data" simulation, this is a little advanced so lets do our best + to sort this out slowly and carefully */ + if(formparse(config, + nextarg, + &config->mimeroot, + &config->mimecurrent, + (subletter == 's')?TRUE:FALSE)) /* 's' is literal string */ + return PARAM_BAD_USE; + if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq)) + return PARAM_BAD_USE; + break; + + case 'g': /* g disables URLglobbing */ + config->globoff = toggle; + break; + + case 'G': /* HTTP GET */ + if(subletter == 'a') { /* --request-target */ + GetStr(&config->request_target, nextarg); + } + else + config->use_httpget = TRUE; + break; + + case 'h': /* h for help */ + if(toggle) { + if(nextarg) { + global->help_category = strdup(nextarg); + if(!global->help_category) + return PARAM_NO_MEM; + } + return PARAM_HELP_REQUESTED; + } + /* we now actually support --no-help too! */ + break; + case 'H': + /* A custom header to append to a list */ + if(nextarg[0] == '@') { + /* read many headers from a file or stdin */ + char *string; + size_t len; + bool use_stdin = !strcmp(&nextarg[1], "-"); + FILE *file = use_stdin?stdin:fopen(&nextarg[1], FOPEN_READTEXT); + if(!file) + warnf(global, "Failed to open %s!\n", &nextarg[1]); + else { + err = file2memory(&string, &len, file); + if(!err && string) { + /* Allow strtok() here since this isn't used threaded */ + /* !checksrc! disable BANNEDFUNC 2 */ + char *h = strtok(string, "\r\n"); + while(h) { + if(subletter == 'p') /* --proxy-header */ + err = add2list(&config->proxyheaders, h); + else + err = add2list(&config->headers, h); + if(err) + break; + h = strtok(NULL, "\r\n"); + } + free(string); + } + if(!use_stdin) + fclose(file); + if(err) + return err; + } + } + else { + if(subletter == 'p') /* --proxy-header */ + err = add2list(&config->proxyheaders, nextarg); + else + err = add2list(&config->headers, nextarg); + if(err) + return err; + } + break; + case 'i': + config->show_headers = toggle; /* show the headers as well in the + general output stream */ + break; + case 'j': + config->cookiesession = toggle; + break; + case 'I': /* --head */ + config->no_body = toggle; + config->show_headers = toggle; + if(SetHTTPrequest(config, + (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET, + &config->httpreq)) + return PARAM_BAD_USE; + break; + case 'J': /* --remote-header-name */ + config->content_disposition = toggle; + break; + case 'k': /* allow insecure SSL connects */ + if(subletter == 'd') /* --doh-insecure */ + config->doh_insecure_ok = toggle; + else + config->insecure_ok = toggle; + break; + case 'K': /* parse config file */ + if(parseconfig(nextarg, global)) { + errorf(global, "cannot read config from '%s'\n", nextarg); + return PARAM_READ_ERROR; + } + break; + case 'l': + config->dirlistonly = toggle; /* only list the names of the FTP dir */ + break; + case 'L': + config->followlocation = toggle; /* Follow Location: HTTP headers */ + switch(subletter) { + case 't': + /* Continue to send authentication (user+password) when following + * locations, even when hostname changed */ + config->unrestricted_auth = toggle; + break; + } + break; + case 'm': + /* specified max time */ + err = str2udouble(&config->timeout, nextarg, LONG_MAX/1000); + if(err) + return err; + break; + case 'M': /* M for manual, huge help */ + if(toggle) { /* --no-manual shows no manual... */ +#ifdef USE_MANUAL + return PARAM_MANUAL_REQUESTED; +#else + warnf(global, + "built-in manual was disabled at build-time!\n"); + return PARAM_OPTION_UNKNOWN; +#endif + } + break; + case 'n': + switch(subletter) { + case 'o': /* use .netrc or URL */ + config->netrc_opt = toggle; + break; + case 'e': /* netrc-file */ + GetStr(&config->netrc_file, nextarg); + break; + default: + /* pick info from .netrc, if this is used for http, curl will + automatically enforce user+password with the request */ + config->netrc = toggle; + break; + } + break; + case 'N': + /* disable the output I/O buffering. note that the option is called + --buffer but is mostly used in the negative form: --no-buffer */ + config->nobuffer = longopt ? !toggle : TRUE; + break; + case 'O': /* --remote-name */ + if(subletter == 'a') { /* --remote-name-all */ + config->default_node_flags = toggle?GETOUT_USEREMOTE:0; + break; + } + else if(subletter == 'b') { /* --output-dir */ + GetStr(&config->output_dir, nextarg); + break; + } + else if(subletter == 'c') { /* --clobber / --no-clobber */ + config->file_clobber_mode = toggle ? CLOBBER_ALWAYS : CLOBBER_NEVER; + break; + } + /* FALLTHROUGH */ + case 'o': /* --output */ + /* output file */ + { + struct getout *url; + if(!config->url_out) + config->url_out = config->url_list; + if(config->url_out) { + /* there's a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE)) + config->url_out = config->url_out->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_out) + /* existing node */ + url = config->url_out; + else + /* there was no free node, create one! */ + config->url_out = url = new_getout(config); + + if(!url) + return PARAM_NO_MEM; + + /* fill in the outfile */ + if('o' == letter) { + if(!*nextarg) { + warnf(global, "output file name has no length\n"); + return PARAM_BAD_USE; + } + GetStr(&url->outfile, nextarg); + url->flags &= ~GETOUT_USEREMOTE; /* switch off */ + } + else { + url->outfile = NULL; /* leave it */ + if(toggle) + url->flags |= GETOUT_USEREMOTE; /* switch on */ + else + url->flags &= ~GETOUT_USEREMOTE; /* switch off */ + } + url->flags |= GETOUT_OUTFILE; + } + break; + case 'P': + /* This makes the FTP sessions use PORT instead of PASV */ + /* use <eth0> or <192.168.10.10> style addresses. Anything except + this will make us try to get the "default" address. + NOTE: this is a changed behavior since the released 4.1! + */ + GetStr(&config->ftpport, nextarg); + break; + case 'p': + /* proxy tunnel for non-http protocols */ + config->proxytunnel = toggle; + break; + + case 'q': /* if used first, already taken care of, we do it like + this so we don't cause an error! */ + break; + case 'Q': + /* QUOTE command to send to FTP server */ + switch(nextarg[0]) { + case '-': + /* prefixed with a dash makes it a POST TRANSFER one */ + nextarg++; + err = add2list(&config->postquote, nextarg); + break; + case '+': + /* prefixed with a plus makes it a just-before-transfer one */ + nextarg++; + err = add2list(&config->prequote, nextarg); + break; + default: + err = add2list(&config->quote, nextarg); + break; + } + if(err) + return err; + break; + case 'r': + /* Specifying a range WITHOUT A DASH will create an illegal HTTP range + (and won't actually be range by definition). The man page previously + claimed that to be a good way, why this code is added to work-around + it. */ + if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) { + char buffer[32]; + curl_off_t off; + if(curlx_strtoofft(nextarg, NULL, 10, &off)) { + warnf(global, "unsupported range point\n"); + return PARAM_BAD_USE; + } + warnf(global, + "A specified range MUST include at least one dash (-). " + "Appending one for you!\n"); + msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off); + Curl_safefree(config->range); + config->range = strdup(buffer); + if(!config->range) + return PARAM_NO_MEM; + } + else { + /* byte range requested */ + const char *tmp_range = nextarg; + while(*tmp_range != '\0') { + if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') { + warnf(global, "Invalid character is found in given range. " + "A specified range MUST have only digits in " + "\'start\'-\'stop\'. The server's response to this " + "request is uncertain.\n"); + break; + } + tmp_range++; + } + GetStr(&config->range, nextarg); + } + break; + case 'R': + /* use remote file's time */ + config->remote_time = toggle; + break; + case 's': + /* don't show progress meter, don't show errors : */ + if(toggle) + global->mute = global->noprogress = TRUE; + else + global->mute = global->noprogress = FALSE; + if(global->showerror < 0) + /* if still on the default value, set showerror to the reverse of + toggle. This is to allow -S and -s to be used in an independent + order but still have the same effect. */ + global->showerror = (!toggle)?TRUE:FALSE; /* toggle off */ + break; + case 'S': + /* show errors */ + global->showerror = toggle?1:0; /* toggle on if used with -s */ + break; + case 't': + /* Telnet options */ + err = add2list(&config->telnet_options, nextarg); + if(err) + return err; + break; + case 'T': + /* we are uploading */ + { + struct getout *url; + if(!config->url_ul) + config->url_ul = config->url_list; + if(config->url_ul) { + /* there's a node here, if it already is filled-in continue to find + an "empty" node */ + while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD)) + config->url_ul = config->url_ul->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_ul) + /* existing node */ + url = config->url_ul; + else + /* there was no free node, create one! */ + config->url_ul = url = new_getout(config); + + if(!url) + return PARAM_NO_MEM; + + url->flags |= GETOUT_UPLOAD; /* mark -T used */ + if(!*nextarg) + url->flags |= GETOUT_NOUPLOAD; + else { + /* "-" equals stdin, but keep the string around for now */ + GetStr(&url->infile, nextarg); + } + } + break; + case 'u': + /* user:password */ + GetStr(&config->userpwd, nextarg); + cleanarg(clearthis); + break; + case 'U': + /* Proxy user:password */ + GetStr(&config->proxyuserpwd, nextarg); + cleanarg(clearthis); + break; + case 'v': + if(toggle) { + /* the '%' thing here will cause the trace get sent to stderr */ + Curl_safefree(global->trace_dump); + global->trace_dump = strdup("%"); + if(!global->trace_dump) + return PARAM_NO_MEM; + if(global->tracetype && (global->tracetype != TRACE_PLAIN)) + warnf(global, + "-v, --verbose overrides an earlier trace/verbose option\n"); + global->tracetype = TRACE_PLAIN; + } + else + /* verbose is disabled here */ + global->tracetype = TRACE_NONE; + break; + case 'V': + if(toggle) /* --no-version yields no output! */ + return PARAM_VERSION_INFO_REQUESTED; + break; + + case 'w': + /* get the output string */ + if('@' == *nextarg) { + /* the data begins with a '@' letter, it means that a file name + or - (stdin) follows */ + FILE *file; + const char *fname; + nextarg++; /* pass the @ */ + if(!strcmp("-", nextarg)) { + fname = "<stdin>"; + file = stdin; + } + else { + fname = nextarg; + file = fopen(nextarg, FOPEN_READTEXT); + } + Curl_safefree(config->writeout); + err = file2string(&config->writeout, file); + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + if(!config->writeout) + warnf(global, "Failed to read %s", fname); + } + else + GetStr(&config->writeout, nextarg); + break; + case 'x': + switch(subletter) { + case 'a': /* --preproxy */ + GetStr(&config->preproxy, nextarg); + break; + default: + /* --proxy */ + GetStr(&config->proxy, nextarg); + config->proxyver = CURLPROXY_HTTP; + break; + } + break; + case 'X': + /* set custom request */ + GetStr(&config->customrequest, nextarg); + break; + case 'y': + /* low speed time */ + err = str2unum(&config->low_speed_time, nextarg); + if(err) + return err; + if(!config->low_speed_limit) + config->low_speed_limit = 1; + break; + case 'Y': + /* low speed limit */ + err = str2unum(&config->low_speed_limit, nextarg); + if(err) + return err; + if(!config->low_speed_time) + config->low_speed_time = 30; + break; + case 'Z': + switch(subletter) { + case '\0': /* --parallel */ + global->parallel = toggle; + break; + case 'b': /* --parallel-max */ + err = str2unum(&global->parallel_max, nextarg); + if(err) + return err; + if(global->parallel_max > MAX_PARALLEL) + global->parallel_max = MAX_PARALLEL; + else if(global->parallel_max < 1) + global->parallel_max = PARALLEL_DEFAULT; + break; + case 'c': /* --parallel-connect */ + global->parallel_connect = toggle; + break; + } + break; + case 'z': /* time condition coming up */ + switch(*nextarg) { + case '+': + nextarg++; + /* FALLTHROUGH */ + default: + /* If-Modified-Since: (section 14.28 in RFC2068) */ + config->timecond = CURL_TIMECOND_IFMODSINCE; + break; + case '-': + /* If-Unmodified-Since: (section 14.24 in RFC2068) */ + config->timecond = CURL_TIMECOND_IFUNMODSINCE; + nextarg++; + break; + case '=': + /* Last-Modified: (section 14.29 in RFC2068) */ + config->timecond = CURL_TIMECOND_LASTMOD; + nextarg++; + break; + } + now = time(NULL); + config->condtime = (curl_off_t)curl_getdate(nextarg, &now); + if(-1 == config->condtime) { + /* now let's see if it is a file name to get the time from instead! */ + curl_off_t filetime = getfiletime(nextarg, global); + if(filetime >= 0) { + /* pull the time out from the file */ + config->condtime = filetime; + } + else { + /* failed, remove time condition */ + config->timecond = CURL_TIMECOND_NONE; + warnf(global, + "Illegal date format for -z, --time-cond (and not " + "a file name). Disabling time condition. " + "See curl_getdate(3) for valid date syntax.\n"); + } + } + break; + default: /* unknown flag */ + return PARAM_OPTION_UNKNOWN; + } + hit = -1; + + } while(!longopt && !singleopt && *++parse && !*usedarg); + + return PARAM_OK; +} + +ParameterError parse_args(struct GlobalConfig *global, int argc, + argv_item_t argv[]) +{ + int i; + bool stillflags; + char *orig_opt = NULL; + ParameterError result = PARAM_OK; + struct OperationConfig *config = global->first; + + for(i = 1, stillflags = TRUE; i < argc && !result; i++) { + orig_opt = curlx_convert_tchar_to_UTF8(argv[i]); + if(!orig_opt) + return PARAM_NO_MEM; + + if(stillflags && ('-' == orig_opt[0])) { + bool passarg; + + if(!strcmp("--", orig_opt)) + /* This indicates the end of the flags and thus enables the + following (URL) argument to start with -. */ + stillflags = FALSE; + else { + char *nextarg = NULL; + if(i < (argc - 1)) { + nextarg = curlx_convert_tchar_to_UTF8(argv[i + 1]); + if(!nextarg) { + curlx_unicodefree(orig_opt); + return PARAM_NO_MEM; + } + } + + result = getparameter(orig_opt, nextarg, &passarg, + global, config); + + curlx_unicodefree(nextarg); + config = global->last; + if(result == PARAM_NEXT_OPERATION) { + /* Reset result as PARAM_NEXT_OPERATION is only used here and not + returned from this function */ + result = PARAM_OK; + + if(config->url_list && config->url_list->url) { + /* Allocate the next config */ + config->next = malloc(sizeof(struct OperationConfig)); + if(config->next) { + /* Initialise the newly created config */ + config_init(config->next); + + /* Set the global config pointer */ + config->next->global = global; + + /* Update the last config pointer */ + global->last = config->next; + + /* Move onto the new config */ + config->next->prev = config; + config = config->next; + } + else + result = PARAM_NO_MEM; + } + } + else if(!result && passarg) + i++; /* we're supposed to skip this */ + } + } + else { + bool used; + + /* Just add the URL please */ + result = getparameter("--url", orig_opt, &used, global, config); + } + + if(!result) + curlx_unicodefree(orig_opt); + } + + if(!result && config->content_disposition) { + if(config->show_headers) + result = PARAM_CONTDISP_SHOW_HEADER; + else if(config->resume_from_current) + result = PARAM_CONTDISP_RESUME_FROM; + } + + if(result && result != PARAM_HELP_REQUESTED && + result != PARAM_MANUAL_REQUESTED && + result != PARAM_VERSION_INFO_REQUESTED && + result != PARAM_ENGINES_REQUESTED) { + const char *reason = param2text(result); + + if(orig_opt && strcmp(":", orig_opt)) + helpf(global->errors, "option %s: %s\n", orig_opt, reason); + else + helpf(global->errors, "%s\n", reason); + } + + curlx_unicodefree(orig_opt); + return result; +} diff --git a/contrib/libs/curl/src/tool_getparam.h b/contrib/libs/curl/src/tool_getparam.h new file mode 100644 index 0000000000..3eb1773918 --- /dev/null +++ b/contrib/libs/curl/src/tool_getparam.h @@ -0,0 +1,71 @@ +#ifndef HEADER_CURL_TOOL_GETPARAM_H +#define HEADER_CURL_TOOL_GETPARAM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +typedef enum { + PARAM_OK = 0, + PARAM_OPTION_AMBIGUOUS, + PARAM_OPTION_UNKNOWN, + PARAM_REQUIRES_PARAMETER, + PARAM_BAD_USE, + PARAM_HELP_REQUESTED, + PARAM_MANUAL_REQUESTED, + PARAM_VERSION_INFO_REQUESTED, + PARAM_ENGINES_REQUESTED, + PARAM_GOT_EXTRA_PARAMETER, + PARAM_BAD_NUMERIC, + PARAM_NEGATIVE_NUMERIC, + PARAM_LIBCURL_DOESNT_SUPPORT, + PARAM_LIBCURL_UNSUPPORTED_PROTOCOL, + PARAM_NO_MEM, + PARAM_NEXT_OPERATION, + PARAM_NO_PREFIX, + PARAM_NUMBER_TOO_LARGE, + PARAM_NO_NOT_BOOLEAN, + PARAM_CONTDISP_SHOW_HEADER, /* --include and --remote-header-name */ + PARAM_CONTDISP_RESUME_FROM, /* --continue-at and --remote-header-name */ + PARAM_READ_ERROR, + PARAM_LAST +} ParameterError; + +struct GlobalConfig; +struct OperationConfig; + +ParameterError getparameter(const char *flag, char *nextarg, + bool *usedarg, + struct GlobalConfig *global, + struct OperationConfig *operation); + +#ifdef UNITTESTS +void parse_cert_parameter(const char *cert_parameter, + char **certname, + char **passphrase); +#endif + +ParameterError parse_args(struct GlobalConfig *config, int argc, + argv_item_t argv[]); + +#endif /* HEADER_CURL_TOOL_GETPARAM_H */ diff --git a/contrib/libs/curl/src/tool_getpass.c b/contrib/libs/curl/src/tool_getpass.c new file mode 100644 index 0000000000..ab112b9bdd --- /dev/null +++ b/contrib/libs/curl/src/tool_getpass.c @@ -0,0 +1,254 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(__AMIGA__) && !defined(__amigaos4__) +# undef HAVE_TERMIOS_H +#endif + +#ifndef HAVE_GETPASS_R +/* this file is only for systems without getpass_r() */ + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#ifdef HAVE_TERMIOS_H +# include <termios.h> +#elif defined(HAVE_TERMIO_H) +# include <termio.h> +#endif + +#ifdef __VMS +# include descrip +# include starlet +# include iodef +#endif + +#ifdef WIN32 +# include <conio.h> +#endif + +#ifdef NETWARE +# ifdef __NOVELL_LIBC__ +# include <screen.h> +# else +# error #include <nwconio.h> +# endif +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include "tool_getpass.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef __VMS +/* VMS implementation */ +char *getpass_r(const char *prompt, char *buffer, size_t buflen) +{ + long sts; + short chan; + + /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4 */ + /* distribution so I created this. May revert back later to */ + /* struct _iosb iosb; */ + struct _iosb + { + short int iosb$w_status; /* status */ + short int iosb$w_bcnt; /* byte count */ + int unused; /* unused */ + } iosb; + + $DESCRIPTOR(ttdesc, "TT"); + + buffer[0] = '\0'; + sts = sys$assign(&ttdesc, &chan, 0, 0); + if(sts & 1) { + sts = sys$qiow(0, chan, + IO$_READPROMPT | IO$M_NOECHO, + &iosb, 0, 0, buffer, buflen, 0, 0, + prompt, strlen(prompt)); + + if((sts & 1) && (iosb.iosb$w_status & 1)) + buffer[iosb.iosb$w_bcnt] = '\0'; + + sys$dassgn(chan); + } + return buffer; /* we always return success */ +} +#define DONE +#endif /* __VMS */ + +#if defined(WIN32) + +char *getpass_r(const char *prompt, char *buffer, size_t buflen) +{ + size_t i; + fputs(prompt, stderr); + + for(i = 0; i < buflen; i++) { + buffer[i] = (char)getch(); + if(buffer[i] == '\r' || buffer[i] == '\n') { + buffer[i] = '\0'; + break; + } + else + if(buffer[i] == '\b') + /* remove this letter and if this is not the first key, remove the + previous one as well */ + i = i - (i >= 1 ? 2 : 1); + } + /* since echo is disabled, print a newline */ + fputs("\n", stderr); + /* if user didn't hit ENTER, terminate buffer */ + if(i == buflen) + buffer[buflen-1] = '\0'; + + return buffer; /* we always return success */ +} +#define DONE +#endif /* WIN32 */ + +#ifdef NETWARE +/* NetWare implementation */ +#ifdef __NOVELL_LIBC__ +char *getpass_r(const char *prompt, char *buffer, size_t buflen) +{ + return getpassword(prompt, buffer, buflen); +} +#else +char *getpass_r(const char *prompt, char *buffer, size_t buflen) +{ + size_t i = 0; + + printf("%s", prompt); + do { + buffer[i++] = getch(); + if(buffer[i-1] == '\b') { + /* remove this letter and if this is not the first key, + remove the previous one as well */ + if(i > 1) { + printf("\b \b"); + i = i - 2; + } + else { + RingTheBell(); + i = i - 1; + } + } + else if(buffer[i-1] != 13) + putchar('*'); + + } while((buffer[i-1] != 13) && (i < buflen)); + buffer[i-1] = '\0'; + printf("\r\n"); + return buffer; +} +#endif /* __NOVELL_LIBC__ */ +#define DONE +#endif /* NETWARE */ + +#ifndef DONE /* not previously provided */ + +#ifdef HAVE_TERMIOS_H +# define struct_term struct termios +#elif defined(HAVE_TERMIO_H) +# define struct_term struct termio +#else +# undef struct_term +#endif + +static bool ttyecho(bool enable, int fd) +{ +#ifdef struct_term + static struct_term withecho; + static struct_term noecho; +#endif + if(!enable) { + /* disable echo by extracting the current 'withecho' mode and remove the + ECHO bit and set back the struct */ +#ifdef HAVE_TERMIOS_H + tcgetattr(fd, &withecho); + noecho = withecho; + noecho.c_lflag &= ~ECHO; + tcsetattr(fd, TCSANOW, &noecho); +#elif defined(HAVE_TERMIO_H) + ioctl(fd, TCGETA, &withecho); + noecho = withecho; + noecho.c_lflag &= ~ECHO; + ioctl(fd, TCSETA, &noecho); +#else + /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */ + (void)fd; + return FALSE; /* not disabled */ +#endif + return TRUE; /* disabled */ + } + /* re-enable echo, assumes we disabled it before (and set the structs we + now use to reset the terminal status) */ +#ifdef HAVE_TERMIOS_H + tcsetattr(fd, TCSAFLUSH, &withecho); +#elif defined(HAVE_TERMIO_H) + ioctl(fd, TCSETA, &withecho); +#else + return FALSE; /* not enabled */ +#endif + return TRUE; /* enabled */ +} + +char *getpass_r(const char *prompt, /* prompt to display */ + char *password, /* buffer to store password in */ + size_t buflen) /* size of buffer to store password in */ +{ + ssize_t nread; + bool disabled; + int fd = open("/dev/tty", O_RDONLY); + if(-1 == fd) + fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */ + + disabled = ttyecho(FALSE, fd); /* disable terminal echo */ + + fputs(prompt, stderr); + nread = read(fd, password, buflen); + if(nread > 0) + password[--nread] = '\0'; /* null-terminate where enter is stored */ + else + password[0] = '\0'; /* got nothing */ + + if(disabled) { + /* if echo actually was disabled, add a newline */ + fputs("\n", stderr); + (void)ttyecho(TRUE, fd); /* enable echo */ + } + + if(STDIN_FILENO != fd) + close(fd); + + return password; /* return pointer to buffer */ +} + +#endif /* DONE */ +#endif /* HAVE_GETPASS_R */ diff --git a/contrib/libs/curl/src/tool_getpass.h b/contrib/libs/curl/src/tool_getpass.h new file mode 100644 index 0000000000..01dc464015 --- /dev/null +++ b/contrib/libs/curl/src/tool_getpass.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_TOOL_GETPASS_H +#define HEADER_CURL_TOOL_GETPASS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifndef HAVE_GETPASS_R +/* If there's a system-provided function named like this, we trust it is + also found in one of the standard headers. */ + +/* + * Returning NULL will abort the continued operation! + */ +char *getpass_r(const char *prompt, char *buffer, size_t buflen); +#endif + +#endif /* HEADER_CURL_TOOL_GETPASS_H */ diff --git a/contrib/libs/curl/src/tool_help.c b/contrib/libs/curl/src/tool_help.c new file mode 100644 index 0000000000..75400d94c1 --- /dev/null +++ b/contrib/libs/curl/src/tool_help.c @@ -0,0 +1,268 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#if defined(HAVE_STRCASECMP) && defined(HAVE_STRINGS_H) +#include <strings.h> +#endif +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_panykey.h" +#include "tool_help.h" +#include "tool_libinfo.h" +#include "tool_version.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef MSDOS +# define USE_WATT32 +#endif + +struct category_descriptors { + const char *opt; + const char *desc; + curlhelp_t category; +}; + +static const struct category_descriptors categories[] = { + {"auth", "Different types of authentication methods", CURLHELP_AUTH}, + {"connection", "Low level networking operations", + CURLHELP_CONNECTION}, + {"curl", "The command line tool itself", CURLHELP_CURL}, + {"dns", "General DNS options", CURLHELP_DNS}, + {"file", "FILE protocol options", CURLHELP_FILE}, + {"ftp", "FTP protocol options", CURLHELP_FTP}, + {"http", "HTTP and HTTPS protocol options", CURLHELP_HTTP}, + {"imap", "IMAP protocol options", CURLHELP_IMAP}, + /* important is left out because it is the default help page */ + {"misc", "Options that don't fit into any other category", CURLHELP_MISC}, + {"output", "Filesystem output", CURLHELP_OUTPUT}, + {"pop3", "POP3 protocol options", CURLHELP_POP3}, + {"post", "HTTP Post specific options", CURLHELP_POST}, + {"proxy", "All options related to proxies", CURLHELP_PROXY}, + {"scp", "SCP protocol options", CURLHELP_SCP}, + {"sftp", "SFTP protocol options", CURLHELP_SFTP}, + {"smtp", "SMTP protocol options", CURLHELP_SMTP}, + {"ssh", "SSH protocol options", CURLHELP_SSH}, + {"telnet", "TELNET protocol options", CURLHELP_TELNET}, + {"tftp", "TFTP protocol options", CURLHELP_TFTP}, + {"tls", "All TLS/SSL related options", CURLHELP_TLS}, + {"upload", "All options for uploads", + CURLHELP_UPLOAD}, + {"verbose", "Options related to any kind of command line output of curl", + CURLHELP_VERBOSE}, + {NULL, NULL, CURLHELP_HIDDEN} +}; + +extern const struct helptxt helptext[]; + +struct feat { + const char *name; + int bitmask; +}; + +static const struct feat feats[] = { + {"AsynchDNS", CURL_VERSION_ASYNCHDNS}, + {"Debug", CURL_VERSION_DEBUG}, + {"TrackMemory", CURL_VERSION_CURLDEBUG}, + {"IDN", CURL_VERSION_IDN}, + {"IPv6", CURL_VERSION_IPV6}, + {"Largefile", CURL_VERSION_LARGEFILE}, + {"Unicode", CURL_VERSION_UNICODE}, + {"SSPI", CURL_VERSION_SSPI}, + {"GSS-API", CURL_VERSION_GSSAPI}, + {"Kerberos", CURL_VERSION_KERBEROS5}, + {"SPNEGO", CURL_VERSION_SPNEGO}, + {"NTLM", CURL_VERSION_NTLM}, + {"NTLM_WB", CURL_VERSION_NTLM_WB}, + {"SSL", CURL_VERSION_SSL}, + {"libz", CURL_VERSION_LIBZ}, + {"brotli", CURL_VERSION_BROTLI}, + {"zstd", CURL_VERSION_ZSTD}, + {"CharConv", CURL_VERSION_CONV}, + {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}, + {"HTTP2", CURL_VERSION_HTTP2}, + {"HTTP3", CURL_VERSION_HTTP3}, + {"UnixSockets", CURL_VERSION_UNIX_SOCKETS}, + {"HTTPS-proxy", CURL_VERSION_HTTPS_PROXY}, + {"MultiSSL", CURL_VERSION_MULTI_SSL}, + {"PSL", CURL_VERSION_PSL}, + {"alt-svc", CURL_VERSION_ALTSVC}, + {"HSTS", CURL_VERSION_HSTS}, + {"gsasl", CURL_VERSION_GSASL}, + {"threadsafe", CURL_VERSION_THREADSAFE}, +}; + +static void print_category(curlhelp_t category) +{ + unsigned int i; + size_t longopt = 5; + size_t longdesc = 5; + + for(i = 0; helptext[i].opt; ++i) { + size_t len; + if(!(helptext[i].categories & category)) + continue; + len = strlen(helptext[i].opt); + if(len > longopt) + longopt = len; + len = strlen(helptext[i].desc); + if(len > longdesc) + longdesc = len; + } + if(longopt + longdesc > 80) + longopt = 80 - longdesc; + + for(i = 0; helptext[i].opt; ++i) + if(helptext[i].categories & category) { + printf(" %-*s %s\n", (int)longopt, helptext[i].opt, helptext[i].desc); + } +} + +/* Prints category if found. If not, it returns 1 */ +static int get_category_content(const char *category) +{ + unsigned int i; + for(i = 0; categories[i].opt; ++i) + if(curl_strequal(categories[i].opt, category)) { + printf("%s: %s\n", categories[i].opt, categories[i].desc); + print_category(categories[i].category); + return 0; + } + return 1; +} + +/* Prints all categories and their description */ +static void get_categories(void) +{ + unsigned int i; + for(i = 0; categories[i].opt; ++i) + printf(" %-11s %s\n", categories[i].opt, categories[i].desc); +} + + +void tool_help(char *category) +{ + puts("Usage: curl [options...] <url>"); + /* If no category was provided */ + if(!category) { + const char *category_note = "\nThis is not the full help, this " + "menu is stripped into categories.\nUse \"--help category\" to get " + "an overview of all categories.\nFor all options use the manual" + " or \"--help all\"."; + print_category(CURLHELP_IMPORTANT); + puts(category_note); + } + /* Lets print everything if "all" was provided */ + else if(curl_strequal(category, "all")) + /* Print everything except hidden */ + print_category(~(CURLHELP_HIDDEN)); + /* Lets handle the string "category" differently to not print an errormsg */ + else if(curl_strequal(category, "category")) + get_categories(); + /* Otherwise print category and handle the case if the cat was not found */ + else if(get_category_content(category)) { + puts("Invalid category provided, here is a list of all categories:\n"); + get_categories(); + } + free(category); +} + +static int +featcomp(const void *p1, const void *p2) +{ + /* The arguments to this function are "pointers to pointers to char", but + the comparison arguments are "pointers to char", hence the following cast + plus dereference */ +#ifdef HAVE_STRCASECMP + return strcasecmp(* (char * const *) p1, * (char * const *) p2); +#elif defined(HAVE_STRCMPI) + return strcmpi(* (char * const *) p1, * (char * const *) p2); +#elif defined(HAVE_STRICMP) + return stricmp(* (char * const *) p1, * (char * const *) p2); +#else + return strcmp(* (char * const *) p1, * (char * const *) p2); +#endif +} + +void tool_version_info(void) +{ + const char *const *proto; + + printf(CURL_ID "%s\n", curl_version()); +#ifdef CURL_PATCHSTAMP + printf("Release-Date: %s, security patched: %s\n", + LIBCURL_TIMESTAMP, CURL_PATCHSTAMP); +#else + printf("Release-Date: %s\n", LIBCURL_TIMESTAMP); +#endif + if(curlinfo->protocols) { + printf("Protocols: "); + for(proto = curlinfo->protocols; *proto; ++proto) { + printf("%s ", *proto); + } + puts(""); /* newline */ + } + if(curlinfo->features) { + char *featp[ sizeof(feats) / sizeof(feats[0]) + 1]; + size_t numfeat = 0; + unsigned int i; + printf("Features:"); + for(i = 0; i < sizeof(feats)/sizeof(feats[0]); i++) { + if(curlinfo->features & feats[i].bitmask) + featp[numfeat++] = (char *)feats[i].name; + } + qsort(&featp[0], numfeat, sizeof(char *), featcomp); + for(i = 0; i< numfeat; i++) + printf(" %s", featp[i]); + puts(""); /* newline */ + } + if(strcmp(CURL_VERSION, curlinfo->version)) { + printf("WARNING: curl and libcurl versions do not match. " + "Functionality may be affected.\n"); + } +} + +void tool_list_engines(void) +{ + CURL *curl = curl_easy_init(); + struct curl_slist *engines = NULL; + + /* Get the list of engines */ + curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines); + + puts("Build-time engines:"); + if(engines) { + for(; engines; engines = engines->next) + printf(" %s\n", engines->data); + } + else { + puts(" <none>"); + } + + /* Cleanup the list of engines */ + curl_slist_free_all(engines); + curl_easy_cleanup(curl); +} diff --git a/contrib/libs/curl/src/tool_help.h b/contrib/libs/curl/src/tool_help.h new file mode 100644 index 0000000000..6fe244e2cf --- /dev/null +++ b/contrib/libs/curl/src/tool_help.h @@ -0,0 +1,74 @@ +#ifndef HEADER_CURL_TOOL_HELP_H +#define HEADER_CURL_TOOL_HELP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +void tool_help(char *category); +void tool_list_engines(void); +void tool_version_info(void); + +typedef unsigned int curlhelp_t; + +struct helptxt { + const char *opt; + const char *desc; + curlhelp_t categories; +}; + +/* + * The bitmask output is generated with the following command + ------------------------------------------------------------ + cd $srcroot/docs/cmdline-opts + ./gen.pl listcats *.d + */ + +#define CURLHELP_HIDDEN 1u << 0u +#define CURLHELP_AUTH 1u << 1u +#define CURLHELP_CONNECTION 1u << 2u +#define CURLHELP_CURL 1u << 3u +#define CURLHELP_DNS 1u << 4u +#define CURLHELP_FILE 1u << 5u +#define CURLHELP_FTP 1u << 6u +#define CURLHELP_HTTP 1u << 7u +#define CURLHELP_IMAP 1u << 8u +#define CURLHELP_IMPORTANT 1u << 9u +#define CURLHELP_MISC 1u << 10u +#define CURLHELP_OUTPUT 1u << 11u +#define CURLHELP_POP3 1u << 12u +#define CURLHELP_POST 1u << 13u +#define CURLHELP_PROXY 1u << 14u +#define CURLHELP_SCP 1u << 15u +#define CURLHELP_SFTP 1u << 16u +#define CURLHELP_SMTP 1u << 17u +#define CURLHELP_SSH 1u << 18u +#define CURLHELP_TELNET 1u << 19u +#define CURLHELP_TFTP 1u << 20u +#define CURLHELP_TLS 1u << 21u +#define CURLHELP_UPLOAD 1u << 22u +#define CURLHELP_VERBOSE 1u << 23u + +extern const struct helptxt helptext[]; + +#endif /* HEADER_CURL_TOOL_HELP_H */ diff --git a/contrib/libs/curl/src/tool_helpers.c b/contrib/libs/curl/src/tool_helpers.c new file mode 100644 index 0000000000..3b2fe9d154 --- /dev/null +++ b/contrib/libs/curl/src/tool_helpers.c @@ -0,0 +1,132 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_getparam.h" +#include "tool_helpers.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* +** Helper functions that are used from more than one source file. +*/ + +const char *param2text(int res) +{ + ParameterError error = (ParameterError)res; + switch(error) { + case PARAM_GOT_EXTRA_PARAMETER: + return "had unsupported trailing garbage"; + case PARAM_OPTION_UNKNOWN: + return "is unknown"; + case PARAM_OPTION_AMBIGUOUS: + return "is ambiguous"; + case PARAM_REQUIRES_PARAMETER: + return "requires parameter"; + case PARAM_BAD_USE: + return "is badly used here"; + case PARAM_BAD_NUMERIC: + return "expected a proper numerical parameter"; + case PARAM_NEGATIVE_NUMERIC: + return "expected a positive numerical parameter"; + case PARAM_LIBCURL_DOESNT_SUPPORT: + return "the installed libcurl version doesn't support this"; + case PARAM_LIBCURL_UNSUPPORTED_PROTOCOL: + return "a specified protocol is unsupported by libcurl"; + case PARAM_NO_MEM: + return "out of memory"; + case PARAM_NO_PREFIX: + return "the given option can't be reversed with a --no- prefix"; + case PARAM_NUMBER_TOO_LARGE: + return "too large number"; + case PARAM_NO_NOT_BOOLEAN: + return "used '--no-' for option that isn't a boolean"; + case PARAM_CONTDISP_SHOW_HEADER: + return "showing headers and --remote-header-name cannot be combined"; + case PARAM_CONTDISP_RESUME_FROM: + return "--continue-at and --remote-header-name cannot be combined"; + case PARAM_READ_ERROR: + return "error encountered when reading a file"; + default: + return "unknown error"; + } +} + +int SetHTTPrequest(struct OperationConfig *config, HttpReq req, HttpReq *store) +{ + /* this mirrors the HttpReq enum in tool_sdecls.h */ + const char *reqname[]= { + "", /* unspec */ + "GET (-G, --get)", + "HEAD (-I, --head)", + "multipart formpost (-F, --form)", + "POST (-d, --data)", + "PUT (-T, --upload-file)" + }; + + if((*store == HTTPREQ_UNSPEC) || + (*store == req)) { + *store = req; + return 0; + } + warnf(config->global, "You can only select one HTTP request method! " + "You asked for both %s and %s.\n", + reqname[req], reqname[*store]); + + return 1; +} + +void customrequest_helper(struct OperationConfig *config, HttpReq req, + char *method) +{ + /* this mirrors the HttpReq enum in tool_sdecls.h */ + const char *dflt[]= { + "GET", + "GET", + "HEAD", + "POST", + "POST", + "PUT" + }; + + if(!method) + ; + else if(curl_strequal(method, dflt[req])) { + notef(config->global, "Unnecessary use of -X or --request, %s is already " + "inferred.\n", dflt[req]); + } + else if(curl_strequal(method, "head")) { + warnf(config->global, + "Setting custom HTTP method to HEAD with -X/--request may not work " + "the way you want. Consider using -I/--head instead.\n"); + } +} diff --git a/contrib/libs/curl/src/tool_helpers.h b/contrib/libs/curl/src/tool_helpers.h new file mode 100644 index 0000000000..cdc84106c8 --- /dev/null +++ b/contrib/libs/curl/src/tool_helpers.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_HELPERS_H +#define HEADER_CURL_TOOL_HELPERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +const char *param2text(int res); + +int SetHTTPrequest(struct OperationConfig *config, HttpReq req, + HttpReq *store); + +void customrequest_helper(struct OperationConfig *config, HttpReq req, + char *method); + +#endif /* HEADER_CURL_TOOL_HELPERS_H */ diff --git a/contrib/libs/curl/src/tool_hugehelp.c b/contrib/libs/curl/src/tool_hugehelp.c new file mode 100644 index 0000000000..bc33e2f143 --- /dev/null +++ b/contrib/libs/curl/src/tool_hugehelp.c @@ -0,0 +1,3 @@ +/* built-in manual is disabled, blank function */ +#include "tool_hugehelp.h" +void hugehelp(void) {} diff --git a/contrib/libs/curl/src/tool_hugehelp.h b/contrib/libs/curl/src/tool_hugehelp.h new file mode 100644 index 0000000000..9d1028094f --- /dev/null +++ b/contrib/libs/curl/src/tool_hugehelp.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_TOOL_HUGEHELP_H +#define HEADER_CURL_TOOL_HUGEHELP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +void hugehelp(void); + +#endif /* HEADER_CURL_TOOL_HUGEHELP_H */ diff --git a/contrib/libs/curl/src/tool_libinfo.c b/contrib/libs/curl/src/tool_libinfo.c new file mode 100644 index 0000000000..039443e239 --- /dev/null +++ b/contrib/libs/curl/src/tool_libinfo.c @@ -0,0 +1,119 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_libinfo.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* global variable definitions, for libcurl run-time info */ + +curl_version_info_data *curlinfo = NULL; +long built_in_protos = 0; + +static struct proto_name_pattern { + const char *proto_name; + long proto_pattern; +} const possibly_built_in[] = { + { "dict", CURLPROTO_DICT }, + { "file", CURLPROTO_FILE }, + { "ftp", CURLPROTO_FTP }, + { "ftps", CURLPROTO_FTPS }, + { "gopher", CURLPROTO_GOPHER }, + { "gophers",CURLPROTO_GOPHERS}, + { "http", CURLPROTO_HTTP }, + { "https", CURLPROTO_HTTPS }, + { "imap", CURLPROTO_IMAP }, + { "imaps", CURLPROTO_IMAPS }, + { "ldap", CURLPROTO_LDAP }, + { "ldaps", CURLPROTO_LDAPS }, + { "mqtt", CURLPROTO_MQTT }, + { "pop3", CURLPROTO_POP3 }, + { "pop3s", CURLPROTO_POP3S }, + { "rtmp", CURLPROTO_RTMP }, + { "rtmps", CURLPROTO_RTMPS }, + { "rtsp", CURLPROTO_RTSP }, + { "scp", CURLPROTO_SCP }, + { "sftp", CURLPROTO_SFTP }, + { "smb", CURLPROTO_SMB }, + { "smbs", CURLPROTO_SMBS }, + { "smtp", CURLPROTO_SMTP }, + { "smtps", CURLPROTO_SMTPS }, + { "telnet", CURLPROTO_TELNET }, + { "tftp", CURLPROTO_TFTP }, + { NULL, 0 } +}; + +/* + * libcurl_info_init: retrieves run-time information about libcurl, + * setting a global pointer 'curlinfo' to libcurl's run-time info + * struct, and a global bit pattern 'built_in_protos' composed of + * CURLPROTO_* bits indicating which protocols are actually built + * into library being used. + */ + +CURLcode get_libcurl_info(void) +{ + const char *const *proto; + + /* Pointer to libcurl's run-time version information */ + curlinfo = curl_version_info(CURLVERSION_NOW); + if(!curlinfo) + return CURLE_FAILED_INIT; + + /* Build CURLPROTO_* bit pattern with libcurl's built-in protocols */ + built_in_protos = 0; + if(curlinfo->protocols) { + for(proto = curlinfo->protocols; *proto; proto++) { + struct proto_name_pattern const *p; + for(p = possibly_built_in; p->proto_name; p++) { + if(curl_strequal(*proto, p->proto_name)) { + built_in_protos |= p->proto_pattern; + break; + } + } + } + } + + return CURLE_OK; +} + +/* + * scheme2protocol() returns the protocol bit for the specified URL scheme + */ +long scheme2protocol(const char *scheme) +{ + struct proto_name_pattern const *p; + for(p = possibly_built_in; p->proto_name; p++) { + if(curl_strequal(scheme, p->proto_name)) + return p->proto_pattern; + } + return 0; +} diff --git a/contrib/libs/curl/src/tool_libinfo.h b/contrib/libs/curl/src/tool_libinfo.h new file mode 100644 index 0000000000..ba6fc0ec1b --- /dev/null +++ b/contrib/libs/curl/src/tool_libinfo.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_LIBINFO_H +#define HEADER_CURL_TOOL_LIBINFO_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* global variable declarations, for libcurl run-time info */ + +extern curl_version_info_data *curlinfo; +extern long built_in_protos; + +CURLcode get_libcurl_info(void); +long scheme2protocol(const char *scheme); + +#endif /* HEADER_CURL_TOOL_LIBINFO_H */ diff --git a/contrib/libs/curl/src/tool_listhelp.c b/contrib/libs/curl/src/tool_listhelp.c new file mode 100644 index 0000000000..f3217be619 --- /dev/null +++ b/contrib/libs/curl/src/tool_listhelp.c @@ -0,0 +1,781 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#include "tool_help.h" + +/* + * DO NOT edit tool_listhelp.c manually. + * This source file is generated with the following command: + + cd $srcroot/docs/cmdline-opts + ./gen.pl listhelp *.d > $srcroot/src/tool_listhelp.c + */ + +const struct helptxt helptext[] = { + {" --abstract-unix-socket <path>", + "Connect via abstract Unix domain socket", + CURLHELP_CONNECTION}, + {" --alt-svc <file name>", + "Enable alt-svc with this cache file", + CURLHELP_HTTP}, + {" --anyauth", + "Pick any authentication method", + CURLHELP_HTTP | CURLHELP_PROXY | CURLHELP_AUTH}, + {"-a, --append", + "Append to target file when uploading", + CURLHELP_FTP | CURLHELP_SFTP}, + {" --aws-sigv4 <provider1[:provider2[:region[:service]]]>", + "Use AWS V4 signature authentication", + CURLHELP_AUTH | CURLHELP_HTTP}, + {" --basic", + "Use HTTP Basic Authentication", + CURLHELP_AUTH}, + {" --cacert <file>", + "CA certificate to verify peer against", + CURLHELP_TLS}, + {" --capath <dir>", + "CA directory to verify peer against", + CURLHELP_TLS}, + {"-E, --cert <certificate[:password]>", + "Client certificate file and password", + CURLHELP_TLS}, + {" --cert-status", + "Verify the status of the server cert via OCSP-staple", + CURLHELP_TLS}, + {" --cert-type <type>", + "Certificate type (DER/PEM/ENG/P12)", + CURLHELP_TLS}, + {" --ciphers <list of ciphers>", + "SSL ciphers to use", + CURLHELP_TLS}, + {" --compressed", + "Request compressed response", + CURLHELP_HTTP}, + {" --compressed-ssh", + "Enable SSH compression", + CURLHELP_SCP | CURLHELP_SSH}, + {"-K, --config <file>", + "Read config from a file", + CURLHELP_CURL}, + {" --connect-timeout <fractional seconds>", + "Maximum time allowed for connection", + CURLHELP_CONNECTION}, + {" --connect-to <HOST1:PORT1:HOST2:PORT2>", + "Connect to host", + CURLHELP_CONNECTION}, + {"-C, --continue-at <offset>", + "Resumed transfer offset", + CURLHELP_CONNECTION}, + {"-b, --cookie <data|filename>", + "Send cookies from string/file", + CURLHELP_HTTP}, + {"-c, --cookie-jar <filename>", + "Write cookies to <filename> after operation", + CURLHELP_HTTP}, + {" --create-dirs", + "Create necessary local directory hierarchy", + CURLHELP_CURL}, + {" --create-file-mode <mode>", + "File mode for created files", + CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_FILE | CURLHELP_UPLOAD}, + {" --crlf", + "Convert LF to CRLF in upload", + CURLHELP_FTP | CURLHELP_SMTP}, + {" --crlfile <file>", + "Use this CRL list", + CURLHELP_TLS}, + {" --curves <algorithm list>", + "(EC) TLS key exchange algorithm(s) to request", + CURLHELP_TLS}, + {"-d, --data <data>", + "HTTP POST data", + CURLHELP_IMPORTANT | CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, + {" --data-ascii <data>", + "HTTP POST ASCII data", + CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, + {" --data-binary <data>", + "HTTP POST binary data", + CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, + {" --data-raw <data>", + "HTTP POST data, '@' allowed", + CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, + {" --data-urlencode <data>", + "HTTP POST data URL encoded", + CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, + {" --delegation <LEVEL>", + "GSS-API delegation permission", + CURLHELP_AUTH}, + {" --digest", + "Use HTTP Digest Authentication", + CURLHELP_PROXY | CURLHELP_AUTH | CURLHELP_HTTP}, + {"-q, --disable", + "Disable .curlrc", + CURLHELP_CURL}, + {" --disable-eprt", + "Inhibit using EPRT or LPRT", + CURLHELP_FTP}, + {" --disable-epsv", + "Inhibit using EPSV", + CURLHELP_FTP}, + {" --disallow-username-in-url", + "Disallow username in URL", + CURLHELP_CURL | CURLHELP_HTTP}, + {" --dns-interface <interface>", + "Interface to use for DNS requests", + CURLHELP_DNS}, + {" --dns-ipv4-addr <address>", + "IPv4 address to use for DNS requests", + CURLHELP_DNS}, + {" --dns-ipv6-addr <address>", + "IPv6 address to use for DNS requests", + CURLHELP_DNS}, + {" --dns-servers <addresses>", + "DNS server addrs to use", + CURLHELP_DNS}, + {" --doh-cert-status", + "Verify the status of the DoH server cert via OCSP-staple", + CURLHELP_DNS | CURLHELP_TLS}, + {" --doh-insecure", + "Allow insecure DoH server connections", + CURLHELP_DNS | CURLHELP_TLS}, + {" --doh-url <URL>", + "Resolve host names over DoH", + CURLHELP_DNS}, + {"-D, --dump-header <filename>", + "Write the received headers to <filename>", + CURLHELP_HTTP | CURLHELP_FTP}, + {" --egd-file <file>", + "EGD socket path for random data", + CURLHELP_TLS}, + {" --engine <name>", + "Crypto engine to use", + CURLHELP_TLS}, + {" --etag-compare <file>", + "Pass an ETag from a file as a custom header", + CURLHELP_HTTP}, + {" --etag-save <file>", + "Parse ETag from a request and save it to a file", + CURLHELP_HTTP}, + {" --expect100-timeout <seconds>", + "How long to wait for 100-continue", + CURLHELP_HTTP}, + {"-f, --fail", + "Fail fast with no output on HTTP errors", + CURLHELP_IMPORTANT | CURLHELP_HTTP}, + {" --fail-early", + "Fail on first transfer error, do not continue", + CURLHELP_CURL}, + {" --fail-with-body", + "Fail on HTTP errors but save the body", + CURLHELP_HTTP | CURLHELP_OUTPUT}, + {" --false-start", + "Enable TLS False Start", + CURLHELP_TLS}, + {"-F, --form <name=content>", + "Specify multipart MIME data", + CURLHELP_HTTP | CURLHELP_UPLOAD}, + {" --form-escape", + "Escape multipart form field/file names using backslash", + CURLHELP_HTTP | CURLHELP_UPLOAD}, + {" --form-string <name=string>", + "Specify multipart MIME data", + CURLHELP_HTTP | CURLHELP_UPLOAD}, + {" --ftp-account <data>", + "Account data string", + CURLHELP_FTP | CURLHELP_AUTH}, + {" --ftp-alternative-to-user <command>", + "String to replace USER [name]", + CURLHELP_FTP}, + {" --ftp-create-dirs", + "Create the remote dirs if not present", + CURLHELP_FTP | CURLHELP_SFTP | CURLHELP_CURL}, + {" --ftp-method <method>", + "Control CWD usage", + CURLHELP_FTP}, + {" --ftp-pasv", + "Use PASV/EPSV instead of PORT", + CURLHELP_FTP}, + {"-P, --ftp-port <address>", + "Use PORT instead of PASV", + CURLHELP_FTP}, + {" --ftp-pret", + "Send PRET before PASV", + CURLHELP_FTP}, + {" --ftp-skip-pasv-ip", + "Skip the IP address for PASV", + CURLHELP_FTP}, + {" --ftp-ssl-ccc", + "Send CCC after authenticating", + CURLHELP_FTP | CURLHELP_TLS}, + {" --ftp-ssl-ccc-mode <active/passive>", + "Set CCC mode", + CURLHELP_FTP | CURLHELP_TLS}, + {" --ftp-ssl-control", + "Require SSL/TLS for FTP login, clear for transfer", + CURLHELP_FTP | CURLHELP_TLS}, + {"-G, --get", + "Put the post data in the URL and use GET", + CURLHELP_HTTP | CURLHELP_UPLOAD}, + {"-g, --globoff", + "Disable URL sequences and ranges using {} and []", + CURLHELP_CURL}, + {" --happy-eyeballs-timeout-ms <milliseconds>", + "Time for IPv6 before trying IPv4", + CURLHELP_CONNECTION}, + {" --haproxy-protocol", + "Send HAProxy PROXY protocol v1 header", + CURLHELP_HTTP | CURLHELP_PROXY}, + {"-I, --head", + "Show document info only", + CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_FILE}, + {"-H, --header <header/@file>", + "Pass custom header(s) to server", + CURLHELP_HTTP}, + {"-h, --help <category>", + "Get help for commands", + CURLHELP_IMPORTANT | CURLHELP_CURL}, + {" --hostpubmd5 <md5>", + "Acceptable MD5 hash of the host public key", + CURLHELP_SFTP | CURLHELP_SCP}, + {" --hostpubsha256 <sha256>", + "Acceptable SHA256 hash of the host public key", + CURLHELP_SFTP | CURLHELP_SCP}, + {" --hsts <file name>", + "Enable HSTS with this cache file", + CURLHELP_HTTP}, + {" --http0.9", + "Allow HTTP 0.9 responses", + CURLHELP_HTTP}, + {"-0, --http1.0", + "Use HTTP 1.0", + CURLHELP_HTTP}, + {" --http1.1", + "Use HTTP 1.1", + CURLHELP_HTTP}, + {" --http2", + "Use HTTP 2", + CURLHELP_HTTP}, + {" --http2-prior-knowledge", + "Use HTTP 2 without HTTP/1.1 Upgrade", + CURLHELP_HTTP}, + {" --http3", + "Use HTTP v3", + CURLHELP_HTTP}, + {" --ignore-content-length", + "Ignore the size of the remote resource", + CURLHELP_HTTP | CURLHELP_FTP}, + {"-i, --include", + "Include protocol response headers in the output", + CURLHELP_IMPORTANT | CURLHELP_VERBOSE}, + {"-k, --insecure", + "Allow insecure server connections", + CURLHELP_TLS | CURLHELP_SFTP | CURLHELP_SCP}, + {" --interface <name>", + "Use network INTERFACE (or address)", + CURLHELP_CONNECTION}, + {"-4, --ipv4", + "Resolve names to IPv4 addresses", + CURLHELP_CONNECTION | CURLHELP_DNS}, + {"-6, --ipv6", + "Resolve names to IPv6 addresses", + CURLHELP_CONNECTION | CURLHELP_DNS}, + {" --json <data>", + "HTTP POST JSON", + CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, + {"-j, --junk-session-cookies", + "Ignore session cookies read from file", + CURLHELP_HTTP}, + {" --keepalive-time <seconds>", + "Interval time for keepalive probes", + CURLHELP_CONNECTION}, + {" --key <key>", + "Private key file name", + CURLHELP_TLS | CURLHELP_SSH}, + {" --key-type <type>", + "Private key file type (DER/PEM/ENG)", + CURLHELP_TLS}, + {" --krb <level>", + "Enable Kerberos with security <level>", + CURLHELP_FTP}, + {" --libcurl <file>", + "Dump libcurl equivalent code of this command line", + CURLHELP_CURL}, + {" --limit-rate <speed>", + "Limit transfer speed to RATE", + CURLHELP_CONNECTION}, + {"-l, --list-only", + "List only mode", + CURLHELP_FTP | CURLHELP_POP3}, + {" --local-port <num/range>", + "Force use of RANGE for local port numbers", + CURLHELP_CONNECTION}, + {"-L, --location", + "Follow redirects", + CURLHELP_HTTP}, + {" --location-trusted", + "Like --location, and send auth to other hosts", + CURLHELP_HTTP | CURLHELP_AUTH}, + {" --login-options <options>", + "Server login options", + CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP | CURLHELP_AUTH}, + {" --mail-auth <address>", + "Originator address of the original email", + CURLHELP_SMTP}, + {" --mail-from <address>", + "Mail from this address", + CURLHELP_SMTP}, + {" --mail-rcpt <address>", + "Mail to this address", + CURLHELP_SMTP}, + {" --mail-rcpt-allowfails", + "Allow RCPT TO command to fail for some recipients", + CURLHELP_SMTP}, + {"-M, --manual", + "Display the full manual", + CURLHELP_CURL}, + {" --max-filesize <bytes>", + "Maximum file size to download", + CURLHELP_CONNECTION}, + {" --max-redirs <num>", + "Maximum number of redirects allowed", + CURLHELP_HTTP}, + {"-m, --max-time <fractional seconds>", + "Maximum time allowed for transfer", + CURLHELP_CONNECTION}, + {" --metalink", + "Process given URLs as metalink XML file", + CURLHELP_MISC}, + {" --negotiate", + "Use HTTP Negotiate (SPNEGO) authentication", + CURLHELP_AUTH | CURLHELP_HTTP}, + {"-n, --netrc", + "Must read .netrc for user name and password", + CURLHELP_CURL}, + {" --netrc-file <filename>", + "Specify FILE for netrc", + CURLHELP_CURL}, + {" --netrc-optional", + "Use either .netrc or URL", + CURLHELP_CURL}, + {"-:, --next", + "Make next URL use its separate set of options", + CURLHELP_CURL}, + {" --no-alpn", + "Disable the ALPN TLS extension", + CURLHELP_TLS | CURLHELP_HTTP}, + {"-N, --no-buffer", + "Disable buffering of the output stream", + CURLHELP_CURL}, + {" --no-clobber", + "Do not overwrite files that already exist", + CURLHELP_CURL | CURLHELP_OUTPUT}, + {" --no-keepalive", + "Disable TCP keepalive on the connection", + CURLHELP_CONNECTION}, + {" --no-npn", + "Disable the NPN TLS extension", + CURLHELP_TLS | CURLHELP_HTTP}, + {" --no-progress-meter", + "Do not show the progress meter", + CURLHELP_VERBOSE}, + {" --no-sessionid", + "Disable SSL session-ID reusing", + CURLHELP_TLS}, + {" --noproxy <no-proxy-list>", + "List of hosts which do not use proxy", + CURLHELP_PROXY}, + {" --ntlm", + "Use HTTP NTLM authentication", + CURLHELP_AUTH | CURLHELP_HTTP}, + {" --ntlm-wb", + "Use HTTP NTLM authentication with winbind", + CURLHELP_AUTH | CURLHELP_HTTP}, + {" --oauth2-bearer <token>", + "OAuth 2 Bearer Token", + CURLHELP_AUTH}, + {"-o, --output <file>", + "Write to file instead of stdout", + CURLHELP_IMPORTANT | CURLHELP_CURL}, + {" --output-dir <dir>", + "Directory to save files in", + CURLHELP_CURL}, + {"-Z, --parallel", + "Perform transfers in parallel", + CURLHELP_CONNECTION | CURLHELP_CURL}, + {" --parallel-immediate", + "Do not wait for multiplexing (with --parallel)", + CURLHELP_CONNECTION | CURLHELP_CURL}, + {" --parallel-max <num>", + "Maximum concurrency for parallel transfers", + CURLHELP_CONNECTION | CURLHELP_CURL}, + {" --pass <phrase>", + "Pass phrase for the private key", + CURLHELP_SSH | CURLHELP_TLS | CURLHELP_AUTH}, + {" --path-as-is", + "Do not squash .. sequences in URL path", + CURLHELP_CURL}, + {" --pinnedpubkey <hashes>", + "FILE/HASHES Public key to verify peer against", + CURLHELP_TLS}, + {" --post301", + "Do not switch to GET after following a 301", + CURLHELP_HTTP | CURLHELP_POST}, + {" --post302", + "Do not switch to GET after following a 302", + CURLHELP_HTTP | CURLHELP_POST}, + {" --post303", + "Do not switch to GET after following a 303", + CURLHELP_HTTP | CURLHELP_POST}, + {" --preproxy [protocol://]host[:port]", + "Use this proxy first", + CURLHELP_PROXY}, + {"-#, --progress-bar", + "Display transfer progress as a bar", + CURLHELP_VERBOSE}, + {" --proto <protocols>", + "Enable/disable PROTOCOLS", + CURLHELP_CONNECTION | CURLHELP_CURL}, + {" --proto-default <protocol>", + "Use PROTOCOL for any URL missing a scheme", + CURLHELP_CONNECTION | CURLHELP_CURL}, + {" --proto-redir <protocols>", + "Enable/disable PROTOCOLS on redirect", + CURLHELP_CONNECTION | CURLHELP_CURL}, + {"-x, --proxy [protocol://]host[:port]", + "Use this proxy", + CURLHELP_PROXY}, + {" --proxy-anyauth", + "Pick any proxy authentication method", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --proxy-basic", + "Use Basic authentication on the proxy", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --proxy-cacert <file>", + "CA certificate to verify peer against for proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-capath <dir>", + "CA directory to verify peer against for proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-cert <cert[:passwd]>", + "Set client certificate for proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-cert-type <type>", + "Client certificate type for HTTPS proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-ciphers <list>", + "SSL ciphers to use for proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-crlfile <file>", + "Set a CRL list for proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-digest", + "Use Digest authentication on the proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-header <header/@file>", + "Pass custom header(s) to proxy", + CURLHELP_PROXY}, + {" --proxy-insecure", + "Do HTTPS proxy connections without verifying the proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-key <key>", + "Private key for HTTPS proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-key-type <type>", + "Private key file type for proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-negotiate", + "Use HTTP Negotiate (SPNEGO) authentication on the proxy", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --proxy-ntlm", + "Use NTLM authentication on the proxy", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --proxy-pass <phrase>", + "Pass phrase for the private key for HTTPS proxy", + CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH}, + {" --proxy-pinnedpubkey <hashes>", + "FILE/HASHES public key to verify proxy with", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-service-name <name>", + "SPNEGO proxy service name", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-ssl-allow-beast", + "Allow security flaw for interop for HTTPS proxy", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-ssl-auto-client-cert", + "Use auto client certificate for proxy (Schannel)", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-tls13-ciphers <ciphersuite list>", + "TLS 1.3 proxy cipher suites", + CURLHELP_PROXY | CURLHELP_TLS}, + {" --proxy-tlsauthtype <type>", + "TLS authentication type for HTTPS proxy", + CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH}, + {" --proxy-tlspassword <string>", + "TLS password for HTTPS proxy", + CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH}, + {" --proxy-tlsuser <name>", + "TLS username for HTTPS proxy", + CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH}, + {" --proxy-tlsv1", + "Use TLSv1 for HTTPS proxy", + CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH}, + {"-U, --proxy-user <user:password>", + "Proxy user and password", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --proxy1.0 <host[:port]>", + "Use HTTP/1.0 proxy on given port", + CURLHELP_PROXY}, + {"-p, --proxytunnel", + "Operate through an HTTP proxy tunnel (using CONNECT)", + CURLHELP_PROXY}, + {" --pubkey <key>", + "SSH Public key file name", + CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_AUTH}, + {"-Q, --quote <command>", + "Send command(s) to server before transfer", + CURLHELP_FTP | CURLHELP_SFTP}, + {" --random-file <file>", + "File for reading random data from", + CURLHELP_MISC}, + {"-r, --range <range>", + "Retrieve only the bytes within RANGE", + CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_SFTP | CURLHELP_FILE}, + {" --rate <max request rate>", + "Request rate for serial transfers", + CURLHELP_CONNECTION}, + {" --raw", + "Do HTTP \"raw\"; no transfer decoding", + CURLHELP_HTTP}, + {"-e, --referer <URL>", + "Referrer URL", + CURLHELP_HTTP}, + {"-J, --remote-header-name", + "Use the header-provided filename", + CURLHELP_OUTPUT}, + {"-O, --remote-name", + "Write output to a file named as the remote file", + CURLHELP_IMPORTANT | CURLHELP_OUTPUT}, + {" --remote-name-all", + "Use the remote file name for all URLs", + CURLHELP_OUTPUT}, + {"-R, --remote-time", + "Set the remote file's time on the local output", + CURLHELP_OUTPUT}, + {" --remove-on-error", + "Remove output file on errors", + CURLHELP_CURL}, + {"-X, --request <method>", + "Specify request method to use", + CURLHELP_CONNECTION}, + {" --request-target <path>", + "Specify the target for this request", + CURLHELP_HTTP}, + {" --resolve <[+]host:port:addr[,addr]...>", + "Resolve the host+port to this address", + CURLHELP_CONNECTION | CURLHELP_DNS}, + {" --retry <num>", + "Retry request if transient problems occur", + CURLHELP_CURL}, + {" --retry-all-errors", + "Retry all errors (use with --retry)", + CURLHELP_CURL}, + {" --retry-connrefused", + "Retry on connection refused (use with --retry)", + CURLHELP_CURL}, + {" --retry-delay <seconds>", + "Wait time between retries", + CURLHELP_CURL}, + {" --retry-max-time <seconds>", + "Retry only within this period", + CURLHELP_CURL}, + {" --sasl-authzid <identity>", + "Identity for SASL PLAIN authentication", + CURLHELP_AUTH}, + {" --sasl-ir", + "Enable initial response in SASL authentication", + CURLHELP_AUTH}, + {" --service-name <name>", + "SPNEGO service name", + CURLHELP_MISC}, + {"-S, --show-error", + "Show error even when -s is used", + CURLHELP_CURL}, + {"-s, --silent", + "Silent mode", + CURLHELP_IMPORTANT | CURLHELP_VERBOSE}, + {" --socks4 <host[:port]>", + "SOCKS4 proxy on given host + port", + CURLHELP_PROXY}, + {" --socks4a <host[:port]>", + "SOCKS4a proxy on given host + port", + CURLHELP_PROXY}, + {" --socks5 <host[:port]>", + "SOCKS5 proxy on given host + port", + CURLHELP_PROXY}, + {" --socks5-basic", + "Enable username/password auth for SOCKS5 proxies", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --socks5-gssapi", + "Enable GSS-API auth for SOCKS5 proxies", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --socks5-gssapi-nec", + "Compatibility with NEC SOCKS5 server", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --socks5-gssapi-service <name>", + "SOCKS5 proxy service name for GSS-API", + CURLHELP_PROXY | CURLHELP_AUTH}, + {" --socks5-hostname <host[:port]>", + "SOCKS5 proxy, pass host name to proxy", + CURLHELP_PROXY}, + {"-Y, --speed-limit <speed>", + "Stop transfers slower than this", + CURLHELP_CONNECTION}, + {"-y, --speed-time <seconds>", + "Trigger 'speed-limit' abort after this time", + CURLHELP_CONNECTION}, + {" --ssl", + "Try SSL/TLS", + CURLHELP_TLS}, + {" --ssl-allow-beast", + "Allow security flaw to improve interop", + CURLHELP_TLS}, + {" --ssl-auto-client-cert", + "Use auto client certificate (Schannel)", + CURLHELP_TLS}, + {" --ssl-no-revoke", + "Disable cert revocation checks (Schannel)", + CURLHELP_TLS}, + {" --ssl-reqd", + "Require SSL/TLS", + CURLHELP_TLS}, + {" --ssl-revoke-best-effort", + "Ignore missing/offline cert CRL dist points", + CURLHELP_TLS}, + {"-2, --sslv2", + "Use SSLv2", + CURLHELP_TLS}, + {"-3, --sslv3", + "Use SSLv3", + CURLHELP_TLS}, + {" --stderr <file>", + "Where to redirect stderr", + CURLHELP_VERBOSE}, + {" --styled-output", + "Enable styled output for HTTP headers", + CURLHELP_VERBOSE}, + {" --suppress-connect-headers", + "Suppress proxy CONNECT response headers", + CURLHELP_PROXY}, + {" --tcp-fastopen", + "Use TCP Fast Open", + CURLHELP_CONNECTION}, + {" --tcp-nodelay", + "Use the TCP_NODELAY option", + CURLHELP_CONNECTION}, + {"-t, --telnet-option <opt=val>", + "Set telnet option", + CURLHELP_TELNET}, + {" --tftp-blksize <value>", + "Set TFTP BLKSIZE option", + CURLHELP_TFTP}, + {" --tftp-no-options", + "Do not send any TFTP options", + CURLHELP_TFTP}, + {"-z, --time-cond <time>", + "Transfer based on a time condition", + CURLHELP_HTTP | CURLHELP_FTP}, + {" --tls-max <VERSION>", + "Set maximum allowed TLS version", + CURLHELP_TLS}, + {" --tls13-ciphers <ciphersuite list>", + "TLS 1.3 cipher suites to use", + CURLHELP_TLS}, + {" --tlsauthtype <type>", + "TLS authentication type", + CURLHELP_TLS | CURLHELP_AUTH}, + {" --tlspassword <string>", + "TLS password", + CURLHELP_TLS | CURLHELP_AUTH}, + {" --tlsuser <name>", + "TLS user name", + CURLHELP_TLS | CURLHELP_AUTH}, + {"-1, --tlsv1", + "Use TLSv1.0 or greater", + CURLHELP_TLS}, + {" --tlsv1.0", + "Use TLSv1.0 or greater", + CURLHELP_TLS}, + {" --tlsv1.1", + "Use TLSv1.1 or greater", + CURLHELP_TLS}, + {" --tlsv1.2", + "Use TLSv1.2 or greater", + CURLHELP_TLS}, + {" --tlsv1.3", + "Use TLSv1.3 or greater", + CURLHELP_TLS}, + {" --tr-encoding", + "Request compressed transfer encoding", + CURLHELP_HTTP}, + {" --trace <file>", + "Write a debug trace to FILE", + CURLHELP_VERBOSE}, + {" --trace-ascii <file>", + "Like --trace, but without hex output", + CURLHELP_VERBOSE}, + {" --trace-time", + "Add time stamps to trace/verbose output", + CURLHELP_VERBOSE}, + {" --unix-socket <path>", + "Connect through this Unix domain socket", + CURLHELP_CONNECTION}, + {"-T, --upload-file <file>", + "Transfer local FILE to destination", + CURLHELP_IMPORTANT | CURLHELP_UPLOAD}, + {" --url <url>", + "URL to work with", + CURLHELP_CURL}, + {"-B, --use-ascii", + "Use ASCII/text transfer", + CURLHELP_MISC}, + {"-u, --user <user:password>", + "Server user and password", + CURLHELP_IMPORTANT | CURLHELP_AUTH}, + {"-A, --user-agent <name>", + "Send User-Agent <name> to server", + CURLHELP_IMPORTANT | CURLHELP_HTTP}, + {"-v, --verbose", + "Make the operation more talkative", + CURLHELP_IMPORTANT | CURLHELP_VERBOSE}, + {"-V, --version", + "Show version number and quit", + CURLHELP_IMPORTANT | CURLHELP_CURL}, + {"-w, --write-out <format>", + "Use output FORMAT after completion", + CURLHELP_VERBOSE}, + {" --xattr", + "Store metadata in extended file attributes", + CURLHELP_MISC}, + { NULL, NULL, CURLHELP_HIDDEN } +}; diff --git a/contrib/libs/curl/src/tool_main.c b/contrib/libs/curl/src/tool_main.c new file mode 100644 index 0000000000..7b6815f635 --- /dev/null +++ b/contrib/libs/curl/src/tool_main.c @@ -0,0 +1,299 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include <sys/stat.h> + +#ifdef WIN32 +#include <tchar.h> +#endif + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#ifdef USE_NSS +#include <nspr.h> +#error #include <plarenas.h> +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_doswin.h" +#include "tool_msgs.h" +#include "tool_operate.h" +#include "tool_panykey.h" +#include "tool_vms.h" +#include "tool_main.h" +#include "tool_libinfo.h" + +/* + * This is low-level hard-hacking memory leak tracking and similar. Using + * the library level code from this client-side is ugly, but we do this + * anyway for convenience. + */ +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef __VMS +/* + * vms_show is a global variable, used in main() as parameter for + * function vms_special_exit() to allow proper curl tool exiting. + * Its value may be set in other tool_*.c source files thanks to + * forward declaration present in tool_vms.h + */ +int vms_show = 0; +#endif + +#ifdef __MINGW32__ +/* + * There seems to be no way to escape "*" in command-line arguments with MinGW + * when command-line argument globbing is enabled under the MSYS shell, so turn + * it off. + */ +int _CRT_glob = 0; +#endif /* __MINGW32__ */ + +/* if we build a static library for unit tests, there is no main() function */ +#ifndef UNITTESTS + +/* + * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are + * open before starting to run. Otherwise, the first three network + * sockets opened by curl could be used for input sources, downloaded data + * or error logs as they will effectively be stdin, stdout and/or stderr. + */ +static void main_checkfds(void) +{ +#ifdef HAVE_PIPE + int fd[2] = { STDIN_FILENO, STDIN_FILENO }; + while(fd[0] == STDIN_FILENO || + fd[0] == STDOUT_FILENO || + fd[0] == STDERR_FILENO || + fd[1] == STDIN_FILENO || + fd[1] == STDOUT_FILENO || + fd[1] == STDERR_FILENO) + if(pipe(fd) < 0) + return; /* Out of handles. This isn't really a big problem now, but + will be when we try to create a socket later. */ + close(fd[0]); + close(fd[1]); +#endif +} + +#ifdef CURLDEBUG +static void memory_tracking_init(void) +{ + char *env; + /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */ + env = curlx_getenv("CURL_MEMDEBUG"); + if(env) { + /* use the value as file name */ + char fname[CURL_MT_LOGFNAME_BUFSIZE]; + if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE) + env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0'; + strcpy(fname, env); + curl_free(env); + curl_dbg_memdebug(fname); + /* this weird stuff here is to make curl_free() get called before + curl_dbg_memdebug() as otherwise memory tracking will log a free() + without an alloc! */ + } + /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ + env = curlx_getenv("CURL_MEMLIMIT"); + if(env) { + char *endptr; + long num = strtol(env, &endptr, 10); + if((endptr != env) && (endptr == env + strlen(env)) && (num > 0)) + curl_dbg_memlimit(num); + curl_free(env); + } +} +#else +# define memory_tracking_init() Curl_nop_stmt +#endif + +/* + * This is the main global constructor for the app. Call this before + * _any_ libcurl usage. If this fails, *NO* libcurl functions may be + * used, or havoc may be the result. + */ +static CURLcode main_init(struct GlobalConfig *config) +{ + CURLcode result = CURLE_OK; + +#if defined(__DJGPP__) || defined(__GO32__) + /* stop stat() wasting time */ + _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; +#endif + + /* Initialise the global config */ + config->showerror = -1; /* Will show errors */ + config->errors = stderr; /* Default errors to stderr */ + config->styled_output = TRUE; /* enable detection */ + config->parallel_max = PARALLEL_DEFAULT; + + /* Allocate the initial operate config */ + config->first = config->last = malloc(sizeof(struct OperationConfig)); + if(config->first) { + /* Perform the libcurl initialization */ + result = curl_global_init(CURL_GLOBAL_DEFAULT); + if(!result) { + /* Get information about libcurl */ + result = get_libcurl_info(); + + if(!result) { + /* Initialise the config */ + config_init(config->first); + config->first->global = config; + } + else { + errorf(config, "error retrieving curl library information\n"); + free(config->first); + } + } + else { + errorf(config, "error initializing curl library\n"); + free(config->first); + } + } + else { + errorf(config, "error initializing curl\n"); + result = CURLE_FAILED_INIT; + } + + return result; +} + +static void free_globalconfig(struct GlobalConfig *config) +{ + Curl_safefree(config->trace_dump); + + if(config->errors_fopened && config->errors) + fclose(config->errors); + config->errors = NULL; + + if(config->trace_fopened && config->trace_stream) + fclose(config->trace_stream); + config->trace_stream = NULL; + + Curl_safefree(config->libcurl); +} + +/* + * This is the main global destructor for the app. Call this after + * _all_ libcurl usage is done. + */ +static void main_free(struct GlobalConfig *config) +{ + /* Cleanup the easy handle */ + /* Main cleanup */ + curl_global_cleanup(); +#ifdef USE_NSS + if(PR_Initialized()) { + /* prevent valgrind from reporting still reachable mem from NSPR arenas */ + PL_ArenaFinish(); + /* prevent valgrind from reporting possibly lost memory (fd cache, ...) */ + PR_Cleanup(); + } +#endif + free_globalconfig(config); + + /* Free the config structures */ + config_free(config->last); + config->first = NULL; + config->last = NULL; +} + +/* +** curl tool main function. +*/ +#ifdef _UNICODE +int wmain(int argc, wchar_t *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ + CURLcode result = CURLE_OK; + struct GlobalConfig global; + memset(&global, 0, sizeof(global)); + +#ifdef WIN32 + /* Undocumented diagnostic option to list the full paths of all loaded + modules. This is purposely pre-init. */ + if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) { + struct curl_slist *item, *head = GetLoadedModulePaths(); + for(item = head; item; item = item->next) + printf("%s\n", item->data); + curl_slist_free_all(head); + return head ? 0 : 1; + } + /* win32_init must be called before other init routines. */ + result = win32_init(); + if(result) { + fprintf(stderr, "curl: (%d) Windows-specific init failed.\n", result); + return result; + } +#endif + + main_checkfds(); + +#if defined(HAVE_SIGNAL) && defined(SIGPIPE) + (void)signal(SIGPIPE, SIG_IGN); +#endif + + /* Initialize memory tracking */ + memory_tracking_init(); + + /* Initialize the curl library - do not call any libcurl functions before + this point */ + result = main_init(&global); + if(!result) { + /* Start our curl operation */ + result = operate(&global, argc, argv); + + /* Perform the main cleanup */ + main_free(&global); + } + +#ifdef WIN32 + /* Flush buffers of all streams opened in write or update mode */ + fflush(NULL); +#endif + +#ifdef __NOVELL_LIBC__ + if(!getenv("_IN_NETWARE_BASH_")) + tool_pressanykey(); +#endif + +#ifdef __VMS + vms_special_exit(result, vms_show); +#else + return (int)result; +#endif +} + +#endif /* ndef UNITTESTS */ diff --git a/contrib/libs/curl/src/tool_main.h b/contrib/libs/curl/src/tool_main.h new file mode 100644 index 0000000000..a1fd1070e9 --- /dev/null +++ b/contrib/libs/curl/src/tool_main.h @@ -0,0 +1,48 @@ +#ifndef HEADER_CURL_TOOL_MAIN_H +#define HEADER_CURL_TOOL_MAIN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define DEFAULT_MAXREDIRS 50L + +#define RETRY_SLEEP_DEFAULT 1000L /* ms */ +#define RETRY_SLEEP_MAX 600000L /* ms == 10 minutes */ + +#define MAX_PARALLEL 300 /* conservative */ +#define PARALLEL_DEFAULT 50 + +#ifndef STDIN_FILENO +# define STDIN_FILENO fileno(stdin) +#endif + +#ifndef STDOUT_FILENO +# define STDOUT_FILENO fileno(stdout) +#endif + +#ifndef STDERR_FILENO +# define STDERR_FILENO fileno(stderr) +#endif + +#endif /* HEADER_CURL_TOOL_MAIN_H */ diff --git a/contrib/libs/curl/src/tool_msgs.c b/contrib/libs/curl/src/tool_msgs.c new file mode 100644 index 0000000000..4900333ff9 --- /dev/null +++ b/contrib/libs/curl/src/tool_msgs.c @@ -0,0 +1,141 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#define WARN_PREFIX "Warning: " +#define NOTE_PREFIX "Note: " +#define ERROR_PREFIX "curl: " + +static void voutf(struct GlobalConfig *config, + const char *prefix, + const char *fmt, + va_list ap) +{ + size_t width = (79 - strlen(prefix)); + if(!config->mute) { + size_t len; + char *ptr; + char *print_buffer; + + print_buffer = curlx_mvaprintf(fmt, ap); + if(!print_buffer) + return; + len = strlen(print_buffer); + + ptr = print_buffer; + while(len > 0) { + fputs(prefix, config->errors); + + if(len > width) { + size_t cut = width-1; + + while(!ISSPACE(ptr[cut]) && cut) { + cut--; + } + if(0 == cut) + /* not a single cutting position was found, just cut it at the + max text width then! */ + cut = width-1; + + (void)fwrite(ptr, cut + 1, 1, config->errors); + fputs("\n", config->errors); + ptr += cut + 1; /* skip the space too */ + len -= cut + 1; + } + else { + fputs(ptr, config->errors); + len = 0; + } + } + curl_free(print_buffer); + } +} + +/* + * Emit 'note' formatted message on configured 'errors' stream, if verbose was + * selected. + */ +void notef(struct GlobalConfig *config, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if(config->tracetype) + voutf(config, NOTE_PREFIX, fmt, ap); + va_end(ap); +} + +/* + * Emit warning formatted message on configured 'errors' stream unless + * mute (--silent) was selected. + */ + +void warnf(struct GlobalConfig *config, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + voutf(config, WARN_PREFIX, fmt, ap); + va_end(ap); +} +/* + * Emit help formatted message on given stream. This is for errors with or + * related to command line arguments. + */ +void helpf(FILE *errors, const char *fmt, ...) +{ + if(fmt) { + va_list ap; + va_start(ap, fmt); + fputs("curl: ", errors); /* prefix it */ + vfprintf(errors, fmt, ap); + va_end(ap); + } + fprintf(errors, "curl: try 'curl --help' " +#ifdef USE_MANUAL + "or 'curl --manual' " +#endif + "for more information\n"); +} + +/* + * Emit error message on error stream if not muted. When errors are not tied + * to command line arguments, use helpf() for such errors. + */ +void errorf(struct GlobalConfig *config, const char *fmt, ...) +{ + if(!config->mute) { + va_list ap; + va_start(ap, fmt); + voutf(config, ERROR_PREFIX, fmt, ap); + va_end(ap); + } +} diff --git a/contrib/libs/curl/src/tool_msgs.h b/contrib/libs/curl/src/tool_msgs.h new file mode 100644 index 0000000000..e35884e9da --- /dev/null +++ b/contrib/libs/curl/src/tool_msgs.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_TOOL_MSGS_H +#define HEADER_CURL_TOOL_MSGS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +void warnf(struct GlobalConfig *config, const char *fmt, ...); +void notef(struct GlobalConfig *config, const char *fmt, ...); +void helpf(FILE *errors, const char *fmt, ...); +void errorf(struct GlobalConfig *config, const char *fmt, ...); + +#endif /* HEADER_CURL_TOOL_MSGS_H */ diff --git a/contrib/libs/curl/src/tool_operate.c b/contrib/libs/curl/src/tool_operate.c new file mode 100644 index 0000000000..87981d21ea --- /dev/null +++ b/contrib/libs/curl/src/tool_operate.c @@ -0,0 +1,2732 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#ifdef HAVE_LOCALE_H +# include <locale.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#elif defined(HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#ifdef __VMS +# include <fabdef.h> +#endif + +#ifdef __AMIGA__ +# include <proto/dos.h> +#endif + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_binmode.h" +#include "tool_cfgable.h" +#include "tool_cb_dbg.h" +#include "tool_cb_hdr.h" +#include "tool_cb_prg.h" +#include "tool_cb_rea.h" +#include "tool_cb_see.h" +#include "tool_cb_wrt.h" +#include "tool_dirhie.h" +#include "tool_doswin.h" +#include "tool_easysrc.h" +#include "tool_filetime.h" +#include "tool_getparam.h" +#include "tool_helpers.h" +#include "tool_findfile.h" +#include "tool_libinfo.h" +#include "tool_main.h" +#include "tool_msgs.h" +#include "tool_operate.h" +#include "tool_operhlp.h" +#include "tool_paramhlp.h" +#include "tool_parsecfg.h" +#include "tool_setopt.h" +#include "tool_sleep.h" +#include "tool_urlglob.h" +#include "tool_util.h" +#include "tool_writeout.h" +#include "tool_xattr.h" +#include "tool_vms.h" +#include "tool_help.h" +#include "tool_hugehelp.h" +#include "tool_progress.h" +#include "dynbuf.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef CURLDEBUG +/* libcurl's debug builds provide an extra function */ +CURLcode curl_easy_perform_ev(CURL *easy); +#endif + +#ifndef O_BINARY +/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in + source code but yet it doesn't ruin anything */ +# define O_BINARY 0 +#endif + +#define CURL_CA_CERT_ERRORMSG \ + "More details here: https://curl.se/docs/sslcerts.html\n\n" \ + "curl failed to verify the legitimacy of the server and therefore " \ + "could not\nestablish a secure connection to it. To learn more about " \ + "this situation and\nhow to fix it, please visit the web page mentioned " \ + "above.\n" + +static CURLcode single_transfer(struct GlobalConfig *global, + struct OperationConfig *config, + CURLSH *share, + bool capath_from_env, + bool *added); +static CURLcode create_transfer(struct GlobalConfig *global, + CURLSH *share, + bool *added); + +static bool is_fatal_error(CURLcode code) +{ + switch(code) { + case CURLE_FAILED_INIT: + case CURLE_OUT_OF_MEMORY: + case CURLE_UNKNOWN_OPTION: + case CURLE_FUNCTION_NOT_FOUND: + case CURLE_BAD_FUNCTION_ARGUMENT: + /* critical error */ + return TRUE; + default: + break; + } + + /* no error or not critical */ + return FALSE; +} + +/* + * Check if a given string is a PKCS#11 URI + */ +static bool is_pkcs11_uri(const char *string) +{ + if(curl_strnequal(string, "pkcs11:", 7)) { + return TRUE; + } + else { + return FALSE; + } +} + +#ifdef __VMS +/* + * get_vms_file_size does what it takes to get the real size of the file + * + * For fixed files, find out the size of the EOF block and adjust. + * + * For all others, have to read the entire file in, discarding the contents. + * Most posted text files will be small, and binary files like zlib archives + * and CD/DVD images should be either a STREAM_LF format or a fixed format. + * + */ +static curl_off_t vms_realfilesize(const char *name, + const struct_stat *stat_buf) +{ + char buffer[8192]; + curl_off_t count; + int ret_stat; + FILE * file; + + /* !checksrc! disable FOPENMODE 1 */ + file = fopen(name, "r"); /* VMS */ + if(!file) { + return 0; + } + count = 0; + ret_stat = 1; + while(ret_stat > 0) { + ret_stat = fread(buffer, 1, sizeof(buffer), file); + if(ret_stat) + count += ret_stat; + } + fclose(file); + + return count; +} + +/* + * + * VmsSpecialSize checks to see if the stat st_size can be trusted and + * if not to call a routine to get the correct size. + * + */ +static curl_off_t VmsSpecialSize(const char *name, + const struct_stat *stat_buf) +{ + switch(stat_buf->st_fab_rfm) { + case FAB$C_VAR: + case FAB$C_VFC: + return vms_realfilesize(name, stat_buf); + break; + default: + return stat_buf->st_size; + } +} +#endif /* __VMS */ + +#define BUFFER_SIZE (100*1024) + +struct per_transfer *transfers; /* first node */ +static struct per_transfer *transfersl; /* last node */ + +/* add_per_transfer creates a new 'per_transfer' node in the linked + list of transfers */ +static CURLcode add_per_transfer(struct per_transfer **per) +{ + struct per_transfer *p; + p = calloc(sizeof(struct per_transfer), 1); + if(!p) + return CURLE_OUT_OF_MEMORY; + if(!transfers) + /* first entry */ + transfersl = transfers = p; + else { + /* make the last node point to the new node */ + transfersl->next = p; + /* make the new node point back to the formerly last node */ + p->prev = transfersl; + /* move the last node pointer to the new entry */ + transfersl = p; + } + *per = p; + all_xfers++; /* count total number of transfers added */ + return CURLE_OK; +} + +/* Remove the specified transfer from the list (and free it), return the next + in line */ +static struct per_transfer *del_per_transfer(struct per_transfer *per) +{ + struct per_transfer *n; + struct per_transfer *p; + DEBUGASSERT(transfers); + DEBUGASSERT(transfersl); + DEBUGASSERT(per); + + n = per->next; + p = per->prev; + + if(p) + p->next = n; + else + transfers = n; + + if(n) + n->prev = p; + else + transfersl = p; + + free(per); + + return n; +} + +static CURLcode pre_transfer(struct GlobalConfig *global, + struct per_transfer *per) +{ + curl_off_t uploadfilesize = -1; + struct_stat fileinfo; + CURLcode result = CURLE_OK; + + if(per->uploadfile && !stdin_upload(per->uploadfile)) { + /* VMS Note: + * + * Reading binary from files can be a problem... Only FIXED, VAR + * etc WITHOUT implied CC will work Others need a \n appended to a + * line + * + * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a + * fixed file with implied CC needs to have a byte added for every + * record processed, this can be derived from Filesize & recordsize + * for VARiable record files the records need to be counted! for + * every record add 1 for linefeed and subtract 2 for the record + * header for VARIABLE header files only the bare record data needs + * to be considered with one appended if implied CC + */ +#ifdef __VMS + /* Calculate the real upload size for VMS */ + per->infd = -1; + if(stat(per->uploadfile, &fileinfo) == 0) { + fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo); + switch(fileinfo.st_fab_rfm) { + case FAB$C_VAR: + case FAB$C_VFC: + case FAB$C_STMCR: + per->infd = open(per->uploadfile, O_RDONLY | O_BINARY); + break; + default: + per->infd = open(per->uploadfile, O_RDONLY | O_BINARY, + "rfm=stmlf", "ctx=stm"); + } + } + if(per->infd == -1) +#else + per->infd = open(per->uploadfile, O_RDONLY | O_BINARY); + if((per->infd == -1) || fstat(per->infd, &fileinfo)) +#endif + { + helpf(global->errors, "Can't open '%s'!\n", per->uploadfile); + if(per->infd != -1) { + close(per->infd); + per->infd = STDIN_FILENO; + } + return CURLE_READ_ERROR; + } + per->infdopen = TRUE; + + /* we ignore file size for char/block devices, sockets, etc. */ + if(S_ISREG(fileinfo.st_mode)) + uploadfilesize = fileinfo.st_size; + + if(uploadfilesize != -1) { + struct OperationConfig *config = per->config; /* for the macro below */ +#ifdef CURL_DISABLE_LIBCURL_OPTION + (void)config; +#endif + my_setopt(per->curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize); + } + per->input.fd = per->infd; + } + return result; +} + +#ifdef __AMIGA__ +static void AmigaSetComment(struct per_transfer *per, + CURLcode result) +{ + struct OutStruct *outs = &per->outs; + if(!result && outs->s_isreg && outs->filename) { + /* Set the url (up to 80 chars) as comment for the file */ + if(strlen(per->this_url) > 78) + per->this_url[79] = '\0'; + SetComment(outs->filename, per->this_url); + } +} +#else +#define AmigaSetComment(x,y) Curl_nop_stmt +#endif + +/* + * Call this after a transfer has completed. + */ +static CURLcode post_per_transfer(struct GlobalConfig *global, + struct per_transfer *per, + CURLcode result, + bool *retryp, + long *delay) /* milliseconds! */ +{ + struct OutStruct *outs = &per->outs; + CURL *curl = per->curl; + struct OperationConfig *config = per->config; + + if(!curl || !config) + return result; + + *retryp = FALSE; + *delay = 0; /* for no retry, keep it zero */ + + if(per->infdopen) + close(per->infd); + +#ifdef __VMS + if(is_vms_shell()) { + /* VMS DCL shell behavior */ + if(!global->showerror) + vms_show = VMSSTS_HIDE; + } + else +#endif + if(!config->synthetic_error && result && global->showerror) { + fprintf(global->errors, "curl: (%d) %s\n", result, + (per->errorbuffer[0]) ? per->errorbuffer : + curl_easy_strerror(result)); + if(result == CURLE_PEER_FAILED_VERIFICATION) + fputs(CURL_CA_CERT_ERRORMSG, global->errors); + } + else if(config->failwithbody) { + /* if HTTP response >= 400, return error */ + long code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); + if(code >= 400) { + if(global->showerror) + fprintf(global->errors, + "curl: (%d) The requested URL returned error: %ld\n", + CURLE_HTTP_RETURNED_ERROR, code); + result = CURLE_HTTP_RETURNED_ERROR; + } + } + /* Set file extended attributes */ + if(!result && config->xattr && outs->fopened && outs->stream) { + int rc = fwrite_xattr(curl, fileno(outs->stream)); + if(rc) + warnf(config->global, "Error setting extended attributes on '%s': %s\n", + outs->filename, strerror(errno)); + } + + if(!result && !outs->stream && !outs->bytes) { + /* we have received no data despite the transfer was successful + ==> force creation of an empty output file (if an output file + was specified) */ + long cond_unmet = 0L; + /* do not create (or even overwrite) the file in case we get no + data because of unmet condition */ + curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet); + if(!cond_unmet && !tool_create_output_file(outs, config)) + result = CURLE_WRITE_ERROR; + } + + if(!outs->s_isreg && outs->stream) { + /* Dump standard stream buffered data */ + int rc = fflush(outs->stream); + if(!result && rc) { + /* something went wrong in the writing process */ + result = CURLE_WRITE_ERROR; + if(global->showerror) + fprintf(global->errors, "curl: (%d) Failed writing body\n", result); + } + } + + /* if retry-max-time is non-zero, make sure we haven't exceeded the + time */ + if(per->retry_numretries && + (!config->retry_maxtime || + (tvdiff(tvnow(), per->retrystart) < + config->retry_maxtime*1000L)) ) { + enum { + RETRY_NO, + RETRY_ALL_ERRORS, + RETRY_TIMEOUT, + RETRY_CONNREFUSED, + RETRY_HTTP, + RETRY_FTP, + RETRY_LAST /* not used */ + } retry = RETRY_NO; + long response = 0; + if((CURLE_OPERATION_TIMEDOUT == result) || + (CURLE_COULDNT_RESOLVE_HOST == result) || + (CURLE_COULDNT_RESOLVE_PROXY == result) || + (CURLE_FTP_ACCEPT_TIMEOUT == result)) + /* retry timeout always */ + retry = RETRY_TIMEOUT; + else if(config->retry_connrefused && + (CURLE_COULDNT_CONNECT == result)) { + long oserrno = 0; + curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno); + if(ECONNREFUSED == oserrno) + retry = RETRY_CONNREFUSED; + } + else if((CURLE_OK == result) || + ((config->failonerror || config->failwithbody) && + (CURLE_HTTP_RETURNED_ERROR == result))) { + /* If it returned OK. _or_ failonerror was enabled and it + returned due to such an error, check for HTTP transient + errors to retry on. */ + long protocol = 0; + curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); + if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) { + /* This was HTTP(S) */ + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + + switch(response) { + case 408: /* Request Timeout */ + case 429: /* Too Many Requests (RFC6585) */ + case 500: /* Internal Server Error */ + case 502: /* Bad Gateway */ + case 503: /* Service Unavailable */ + case 504: /* Gateway Timeout */ + retry = RETRY_HTTP; + /* + * At this point, we have already written data to the output + * file (or terminal). If we write to a file, we must rewind + * or close/re-open the file so that the next attempt starts + * over from the beginning. + * + * TODO: similar action for the upload case. We might need + * to start over reading from a previous point if we have + * uploaded something when this was returned. + */ + break; + } + } + } /* if CURLE_OK */ + else if(result) { + long protocol = 0; + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); + + if((protocol == CURLPROTO_FTP || protocol == CURLPROTO_FTPS) && + response / 100 == 4) + /* + * This is typically when the FTP server only allows a certain + * amount of users and we are not one of them. All 4xx codes + * are transient. + */ + retry = RETRY_FTP; + } + + if(result && !retry && config->retry_all_errors) + retry = RETRY_ALL_ERRORS; + + if(retry) { + long sleeptime = 0; + curl_off_t retry_after = 0; + static const char * const m[]={ + NULL, + "(retrying all errors)", + ": timeout", + ": connection refused", + ": HTTP error", + ": FTP error" + }; + + sleeptime = per->retry_sleep; + if(RETRY_HTTP == retry) { + curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after); + if(retry_after) { + /* store in a 'long', make sure it doesn't overflow */ + if(retry_after > LONG_MAX/1000) + sleeptime = LONG_MAX; + else + sleeptime = (long)retry_after * 1000; /* milliseconds */ + + /* if adding retry_after seconds to the process would exceed the + maximum time allowed for retrying, then exit the retries right + away */ + if(config->retry_maxtime) { + curl_off_t seconds = tvdiff(tvnow(), per->retrystart)/1000; + + if((CURL_OFF_T_MAX - retry_after < seconds) || + (seconds + retry_after > config->retry_maxtime)) { + warnf(config->global, "The Retry-After: time would " + "make this command line exceed the maximum allowed time " + "for retries."); + goto noretry; + } + } + } + } + warnf(config->global, "Problem %s. " + "Will retry in %ld seconds. " + "%ld retries left.\n", + m[retry], sleeptime/1000L, per->retry_numretries); + + per->retry_numretries--; + if(!config->retry_delay) { + per->retry_sleep *= 2; + if(per->retry_sleep > RETRY_SLEEP_MAX) + per->retry_sleep = RETRY_SLEEP_MAX; + } + if(outs->bytes && outs->filename && outs->stream) { + int rc; + /* We have written data to an output file, we truncate file + */ + if(!global->mute) + fprintf(global->errors, "Throwing away %" + CURL_FORMAT_CURL_OFF_T " bytes\n", + outs->bytes); + fflush(outs->stream); + /* truncate file at the position where we started appending */ +#ifdef HAVE_FTRUNCATE + if(ftruncate(fileno(outs->stream), outs->init)) { + /* when truncate fails, we can't just append as then we'll + create something strange, bail out */ + if(global->showerror) + fprintf(global->errors, + "curl: (23) Failed to truncate file\n"); + return CURLE_WRITE_ERROR; + } + /* now seek to the end of the file, the position where we + just truncated the file in a large file-safe way */ + rc = fseek(outs->stream, 0, SEEK_END); +#else + /* ftruncate is not available, so just reposition the file + to the location we would have truncated it. This won't + work properly with large files on 32-bit systems, but + most of those will have ftruncate. */ + rc = fseek(outs->stream, (long)outs->init, SEEK_SET); +#endif + if(rc) { + if(global->showerror) + fprintf(global->errors, + "curl: (23) Failed seeking to end of file\n"); + return CURLE_WRITE_ERROR; + } + outs->bytes = 0; /* clear for next round */ + } + *retryp = TRUE; + *delay = sleeptime; + return CURLE_OK; + } + } /* if retry_numretries */ + noretry: + + if((global->progressmode == CURL_PROGRESS_BAR) && + per->progressbar.calls) + /* if the custom progress bar has been displayed, we output a + newline here */ + fputs("\n", per->progressbar.out); + + /* Close the outs file */ + if(outs->fopened && outs->stream) { + int rc = fclose(outs->stream); + if(!result && rc) { + /* something went wrong in the writing process */ + result = CURLE_WRITE_ERROR; + if(global->showerror) + fprintf(global->errors, "curl: (%d) Failed writing body\n", result); + } + if(result && config->rm_partial) { + notef(global, "Removing output file: %s\n", outs->filename); + unlink(outs->filename); + } + } + + AmigaSetComment(per, result); + + /* File time can only be set _after_ the file has been closed */ + if(!result && config->remote_time && outs->s_isreg && outs->filename) { + /* Ask libcurl if we got a remote file time */ + curl_off_t filetime = -1; + curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime); + setfiletime(filetime, outs->filename, global); + } + + /* Write the --write-out data before cleanup but after result is final */ + if(config->writeout) + ourWriteOut(config->writeout, per, result); + + /* Close function-local opened file descriptors */ + if(per->heads.fopened && per->heads.stream) + fclose(per->heads.stream); + + if(per->heads.alloc_filename) + Curl_safefree(per->heads.filename); + + if(per->etag_save.fopened && per->etag_save.stream) + fclose(per->etag_save.stream); + + if(per->etag_save.alloc_filename) + Curl_safefree(per->etag_save.filename); + + curl_easy_cleanup(per->curl); + if(outs->alloc_filename) + free(outs->filename); + free(per->this_url); + free(per->outfile); + free(per->uploadfile); + + return result; +} + +static void single_transfer_cleanup(struct OperationConfig *config) +{ + if(config) { + struct State *state = &config->state; + if(state->urls) { + /* Free list of remaining URLs */ + glob_cleanup(state->urls); + state->urls = NULL; + } + Curl_safefree(state->outfiles); + Curl_safefree(state->httpgetfields); + Curl_safefree(state->uploadfile); + if(state->inglob) { + /* Free list of globbed upload files */ + glob_cleanup(state->inglob); + state->inglob = NULL; + } + } +} + +/* + * Return the proto bit for the scheme used in the given URL + */ +static long url_proto(char *url) +{ + CURLU *uh = curl_url(); + long proto = 0; + if(uh) { + if(url) { + if(!curl_url_set(uh, CURLUPART_URL, url, + CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME)) { + char *schemep = NULL; + if(!curl_url_get(uh, CURLUPART_SCHEME, &schemep, + CURLU_DEFAULT_SCHEME) && + schemep) { + proto = scheme2protocol(schemep); + curl_free(schemep); + } + } + } + curl_url_cleanup(uh); + } + return proto; +} + +/* create the next (singular) transfer */ + +static CURLcode single_transfer(struct GlobalConfig *global, + struct OperationConfig *config, + CURLSH *share, + bool capath_from_env, + bool *added) +{ + CURLcode result = CURLE_OK; + struct getout *urlnode; + bool orig_noprogress = global->noprogress; + bool orig_isatty = global->isatty; + struct State *state = &config->state; + char *httpgetfields = state->httpgetfields; + *added = FALSE; /* not yet */ + + if(config->postfields) { + if(config->use_httpget) { + if(!httpgetfields) { + /* Use the postfields data for a http get */ + httpgetfields = state->httpgetfields = strdup(config->postfields); + Curl_safefree(config->postfields); + if(!httpgetfields) { + errorf(global, "out of memory\n"); + result = CURLE_OUT_OF_MEMORY; + } + else if(SetHTTPrequest(config, + (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET), + &config->httpreq)) { + result = CURLE_FAILED_INIT; + } + } + } + else { + if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) + result = CURLE_FAILED_INIT; + } + if(result) { + single_transfer_cleanup(config); + return result; + } + } + if(!state->urlnode) { + /* first time caller, setup things */ + state->urlnode = config->url_list; + state->infilenum = 1; + } + + while(config->state.urlnode) { + static bool warn_more_options = FALSE; + char *infiles; /* might be a glob pattern */ + struct URLGlob *inglob = state->inglob; + urlnode = config->state.urlnode; + + /* urlnode->url is the full URL (it might be NULL) */ + + if(!urlnode->url) { + /* This node has no URL. Free node data without destroying the + node itself nor modifying next pointer and continue to next */ + Curl_safefree(urlnode->outfile); + Curl_safefree(urlnode->infile); + urlnode->flags = 0; + config->state.urlnode = urlnode->next; + state->up = 0; + if(!warn_more_options) { + /* only show this once */ + warnf(config->global, "Got more output options than URLs\n"); + warn_more_options = TRUE; + } + continue; /* next URL please */ + } + + /* save outfile pattern before expansion */ + if(urlnode->outfile && !state->outfiles) { + state->outfiles = strdup(urlnode->outfile); + if(!state->outfiles) { + errorf(global, "out of memory\n"); + result = CURLE_OUT_OF_MEMORY; + break; + } + } + + infiles = urlnode->infile; + + if(!config->globoff && infiles && !inglob) { + /* Unless explicitly shut off */ + result = glob_url(&inglob, infiles, &state->infilenum, + global->showerror?global->errors:NULL); + if(result) + break; + config->state.inglob = inglob; + } + + { + unsigned long urlnum; + + if(!state->up && !infiles) + Curl_nop_stmt; + else { + if(!state->uploadfile) { + if(inglob) { + result = glob_next_url(&state->uploadfile, inglob); + if(result == CURLE_OUT_OF_MEMORY) + errorf(global, "out of memory\n"); + } + else if(!state->up) { + state->uploadfile = strdup(infiles); + if(!state->uploadfile) { + errorf(global, "out of memory\n"); + result = CURLE_OUT_OF_MEMORY; + } + } + } + if(result) + break; + } + + if(!state->urlnum) { + if(!config->globoff) { + /* Unless explicitly shut off, we expand '{...}' and '[...]' + expressions and return total number of URLs in pattern set */ + result = glob_url(&state->urls, urlnode->url, &state->urlnum, + global->showerror?global->errors:NULL); + if(result) + break; + urlnum = state->urlnum; + } + else + urlnum = 1; /* without globbing, this is a single URL */ + } + else + urlnum = state->urlnum; + + if(state->up < state->infilenum) { + struct per_transfer *per = NULL; + struct OutStruct *outs; + struct InStruct *input; + struct OutStruct *heads; + struct OutStruct *etag_save; + struct HdrCbData *hdrcbdata = NULL; + struct OutStruct etag_first; + long use_proto; + CURL *curl; + + /* --etag-save */ + memset(&etag_first, 0, sizeof(etag_first)); + etag_save = &etag_first; + etag_save->stream = stdout; + + /* --etag-compare */ + if(config->etag_compare_file) { + char *etag_from_file = NULL; + char *header = NULL; + ParameterError pe; + + /* open file for reading: */ + FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT); + if(!file && !config->etag_save_file) { + errorf(global, + "Failed to open %s\n", config->etag_compare_file); + result = CURLE_READ_ERROR; + break; + } + + if((PARAM_OK == file2string(&etag_from_file, file)) && + etag_from_file) { + header = aprintf("If-None-Match: %s", etag_from_file); + Curl_safefree(etag_from_file); + } + else + header = aprintf("If-None-Match: \"\""); + + if(!header) { + if(file) + fclose(file); + errorf(global, + "Failed to allocate memory for custom etag header\n"); + result = CURLE_OUT_OF_MEMORY; + break; + } + + /* add Etag from file to list of custom headers */ + pe = add2list(&config->headers, header); + Curl_safefree(header); + + if(file) + fclose(file); + if(pe != PARAM_OK) { + result = CURLE_OUT_OF_MEMORY; + break; + } + } + + if(config->etag_save_file) { + /* open file for output: */ + if(strcmp(config->etag_save_file, "-")) { + FILE *newfile = fopen(config->etag_save_file, "wb"); + if(!newfile) { + warnf(global, "Failed creating file for saving etags: \"%s\". " + "Skip this transfer\n", config->etag_save_file); + Curl_safefree(state->outfiles); + glob_cleanup(state->urls); + return CURLE_OK; + } + else { + etag_save->filename = config->etag_save_file; + etag_save->s_isreg = TRUE; + etag_save->fopened = TRUE; + etag_save->stream = newfile; + } + } + else { + /* always use binary mode for protocol header output */ + set_binmode(etag_save->stream); + } + } + + curl = curl_easy_init(); + if(curl) + result = add_per_transfer(&per); + else + result = CURLE_OUT_OF_MEMORY; + if(result) { + curl_easy_cleanup(curl); + if(etag_save->fopened) + fclose(etag_save->stream); + break; + } + per->etag_save = etag_first; /* copy the whole struct */ + if(state->uploadfile) { + per->uploadfile = strdup(state->uploadfile); + if(!per->uploadfile) { + curl_easy_cleanup(curl); + result = CURLE_OUT_OF_MEMORY; + break; + } + if(SetHTTPrequest(config, HTTPREQ_PUT, &config->httpreq)) { + Curl_safefree(per->uploadfile); + curl_easy_cleanup(curl); + result = CURLE_FAILED_INIT; + break; + } + } + *added = TRUE; + per->config = config; + per->curl = curl; + per->urlnum = urlnode->num; + + /* default headers output stream is stdout */ + heads = &per->heads; + heads->stream = stdout; + + /* Single header file for all URLs */ + if(config->headerfile) { + /* open file for output: */ + if(strcmp(config->headerfile, "-")) { + FILE *newfile; + newfile = fopen(config->headerfile, per->prev == NULL?"wb":"ab"); + if(!newfile) { + warnf(global, "Failed to open %s\n", config->headerfile); + result = CURLE_WRITE_ERROR; + break; + } + else { + heads->filename = config->headerfile; + heads->s_isreg = TRUE; + heads->fopened = TRUE; + heads->stream = newfile; + } + } + else { + /* always use binary mode for protocol header output */ + set_binmode(heads->stream); + } + } + + hdrcbdata = &per->hdrcbdata; + + outs = &per->outs; + input = &per->input; + + per->outfile = NULL; + per->infdopen = FALSE; + per->infd = STDIN_FILENO; + + /* default output stream is stdout */ + outs->stream = stdout; + + if(state->urls) { + result = glob_next_url(&per->this_url, state->urls); + if(result) + break; + } + else if(!state->li) { + per->this_url = strdup(urlnode->url); + if(!per->this_url) { + result = CURLE_OUT_OF_MEMORY; + break; + } + } + else + per->this_url = NULL; + if(!per->this_url) + break; + + if(state->outfiles) { + per->outfile = strdup(state->outfiles); + if(!per->outfile) { + result = CURLE_OUT_OF_MEMORY; + break; + } + } + + if(((urlnode->flags&GETOUT_USEREMOTE) || + (per->outfile && strcmp("-", per->outfile)))) { + + /* + * We have specified a file name to store the result in, or we have + * decided we want to use the remote file name. + */ + + if(!per->outfile) { + /* extract the file name from the URL */ + result = get_url_file_name(&per->outfile, per->this_url); + if(result) { + errorf(global, "Failed to extract a sensible file name" + " from the URL to use for storage!\n"); + break; + } + if(!*per->outfile && !config->content_disposition) { + errorf(global, "Remote file name has no length!\n"); + result = CURLE_WRITE_ERROR; + break; + } + } + else if(state->urls) { + /* fill '#1' ... '#9' terms from URL pattern */ + char *storefile = per->outfile; + result = glob_match_url(&per->outfile, storefile, state->urls); + Curl_safefree(storefile); + if(result) { + /* bad globbing */ + warnf(global, "bad output glob!\n"); + break; + } + if(!*per->outfile) { + warnf(global, "output glob produces empty string!\n"); + result = CURLE_WRITE_ERROR; + break; + } + } + + if(config->output_dir && *config->output_dir) { + char *d = aprintf("%s/%s", config->output_dir, per->outfile); + if(!d) { + result = CURLE_WRITE_ERROR; + break; + } + free(per->outfile); + per->outfile = d; + } + /* Create the directory hierarchy, if not pre-existent to a multiple + file output call */ + + if(config->create_dirs) { + result = create_dir_hierarchy(per->outfile, global->errors); + /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */ + if(result) + break; + } + + if((urlnode->flags & GETOUT_USEREMOTE) + && config->content_disposition) { + /* Our header callback MIGHT set the filename */ + DEBUGASSERT(!outs->filename); + } + + if(config->resume_from_current) { + /* We're told to continue from where we are now. Get the size + of the file as it is now and open it for append instead */ + struct_stat fileinfo; + /* VMS -- Danger, the filesize is only valid for stream files */ + if(0 == stat(per->outfile, &fileinfo)) + /* set offset to current file size: */ + config->resume_from = fileinfo.st_size; + else + /* let offset be 0 */ + config->resume_from = 0; + } + + if(config->resume_from) { +#ifdef __VMS + /* open file for output, forcing VMS output format into stream + mode which is needed for stat() call above to always work. */ + FILE *file = fopen(outfile, "ab", + "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0"); +#else + /* open file for output: */ + FILE *file = fopen(per->outfile, "ab"); +#endif + if(!file) { + errorf(global, "Can't open '%s'!\n", per->outfile); + result = CURLE_WRITE_ERROR; + break; + } + outs->fopened = TRUE; + outs->stream = file; + outs->init = config->resume_from; + } + else { + outs->stream = NULL; /* open when needed */ + } + outs->filename = per->outfile; + outs->s_isreg = TRUE; + } + + if(per->uploadfile && !stdin_upload(per->uploadfile)) { + /* + * We have specified a file to upload and it isn't "-". + */ + char *nurl = add_file_name_to_url(per->this_url, per->uploadfile); + if(!nurl) { + result = CURLE_OUT_OF_MEMORY; + break; + } + per->this_url = nurl; + } + else if(per->uploadfile && stdin_upload(per->uploadfile)) { + /* count to see if there are more than one auth bit set + in the authtype field */ + int authbits = 0; + int bitcheck = 0; + while(bitcheck < 32) { + if(config->authtype & (1UL << bitcheck++)) { + authbits++; + if(authbits > 1) { + /* more than one, we're done! */ + break; + } + } + } + + /* + * If the user has also selected --anyauth or --proxy-anyauth + * we should warn them. + */ + if(config->proxyanyauth || (authbits>1)) { + warnf(global, + "Using --anyauth or --proxy-anyauth with upload from stdin" + " involves a big risk of it not working. Use a temporary" + " file or a fixed auth type instead!\n"); + } + + DEBUGASSERT(per->infdopen == FALSE); + DEBUGASSERT(per->infd == STDIN_FILENO); + + set_binmode(stdin); + if(!strcmp(per->uploadfile, ".")) { + if(curlx_nonblock((curl_socket_t)per->infd, TRUE) < 0) + warnf(global, + "fcntl failed on fd=%d: %s\n", per->infd, strerror(errno)); + } + } + + if(per->uploadfile && config->resume_from_current) + config->resume_from = -1; /* -1 will then force get-it-yourself */ + + if(output_expected(per->this_url, per->uploadfile) && outs->stream && + isatty(fileno(outs->stream))) + /* we send the output to a tty, therefore we switch off the progress + meter */ + per->noprogress = global->noprogress = global->isatty = TRUE; + else { + /* progress meter is per download, so restore config + values */ + per->noprogress = global->noprogress = orig_noprogress; + global->isatty = orig_isatty; + } + + if(httpgetfields) { + char *urlbuffer; + /* Find out whether the url contains a file name */ + const char *pc = strstr(per->this_url, "://"); + char sep = '?'; + if(pc) + pc += 3; + else + pc = per->this_url; + + pc = strrchr(pc, '/'); /* check for a slash */ + + if(pc) { + /* there is a slash present in the URL */ + + if(strchr(pc, '?')) + /* Ouch, there's already a question mark in the URL string, we + then append the data with an ampersand separator instead! */ + sep = '&'; + } + /* + * Then append ? followed by the get fields to the url. + */ + if(pc) + urlbuffer = aprintf("%s%c%s", per->this_url, sep, httpgetfields); + else + /* Append / before the ? to create a well-formed url + if the url contains a hostname only + */ + urlbuffer = aprintf("%s/?%s", per->this_url, httpgetfields); + + if(!urlbuffer) { + result = CURLE_OUT_OF_MEMORY; + break; + } + + Curl_safefree(per->this_url); /* free previous URL */ + per->this_url = urlbuffer; /* use our new URL instead! */ + } + + if(!global->errors) + global->errors = stderr; + + if((!per->outfile || !strcmp(per->outfile, "-")) && + !config->use_ascii) { + /* We get the output to stdout and we have not got the ASCII/text + flag, then set stdout to be binary */ + set_binmode(stdout); + } + + /* explicitly passed to stdout means okaying binary gunk */ + config->terminal_binary_ok = + (per->outfile && !strcmp(per->outfile, "-")); + + /* Avoid having this setopt added to the --libcurl source output. */ + result = curl_easy_setopt(curl, CURLOPT_SHARE, share); + if(result) + break; + + /* here */ + use_proto = url_proto(per->this_url); +#if 0 + if(!(use_proto & built_in_protos)) { + warnf(global, "URL is '%s' but no support for the scheme\n", + per->this_url); + } +#endif + + if(!config->tcp_nodelay) + my_setopt(curl, CURLOPT_TCP_NODELAY, 0L); + + if(config->tcp_fastopen) + my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L); + + /* where to store */ + my_setopt(curl, CURLOPT_WRITEDATA, per); + my_setopt(curl, CURLOPT_INTERLEAVEDATA, per); + + /* what call to write */ + my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb); + + /* for uploads */ + input->config = config; + /* Note that if CURLOPT_READFUNCTION is fread (the default), then + * lib/telnet.c will Curl_poll() on the input file descriptor + * rather than calling the READFUNCTION at regular intervals. + * The circumstances in which it is preferable to enable this + * behavior, by omitting to set the READFUNCTION & READDATA options, + * have not been determined. + */ + my_setopt(curl, CURLOPT_READDATA, input); + /* what call to read */ + my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb); + + /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what + CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */ + my_setopt(curl, CURLOPT_SEEKDATA, input); + my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb); + + if(config->recvpersecond && + (config->recvpersecond < BUFFER_SIZE)) + /* use a smaller sized buffer for better sleeps */ + my_setopt(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond); + else + my_setopt(curl, CURLOPT_BUFFERSIZE, (long)BUFFER_SIZE); + + my_setopt_str(curl, CURLOPT_URL, per->this_url); + my_setopt(curl, CURLOPT_NOPROGRESS, global->noprogress?1L:0L); + if(config->no_body) + my_setopt(curl, CURLOPT_NOBODY, 1L); + + if(config->oauth_bearer) + my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer); + + my_setopt_str(curl, CURLOPT_PROXY, config->proxy); + + if(config->proxy && result) { + errorf(global, "proxy support is disabled in this libcurl\n"); + config->synthetic_error = TRUE; + result = CURLE_NOT_BUILT_IN; + break; + } + + /* new in libcurl 7.5 */ + if(config->proxy) + my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver); + + my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd); + + /* new in libcurl 7.3 */ + my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel?1L:0L); + + /* new in libcurl 7.52.0 */ + if(config->preproxy) + my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy); + + /* new in libcurl 7.10.6 */ + if(config->proxyanyauth) + my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, + (long)CURLAUTH_ANY); + else if(config->proxynegotiate) + my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, + (long)CURLAUTH_GSSNEGOTIATE); + else if(config->proxyntlm) + my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, + (long)CURLAUTH_NTLM); + else if(config->proxydigest) + my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, + (long)CURLAUTH_DIGEST); + else if(config->proxybasic) + my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, + (long)CURLAUTH_BASIC); + + /* new in libcurl 7.19.4 */ + my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy); + + my_setopt(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS, + config->suppress_connect_headers?1L:0L); + + my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror?1L:0L); + my_setopt(curl, CURLOPT_REQUEST_TARGET, config->request_target); + my_setopt(curl, CURLOPT_UPLOAD, per->uploadfile?1L:0L); + my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly?1L:0L); + my_setopt(curl, CURLOPT_APPEND, config->ftp_append?1L:0L); + + if(config->netrc_opt) + my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL); + else if(config->netrc || config->netrc_file) + my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_REQUIRED); + else + my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_IGNORED); + + if(config->netrc_file) + my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file); + + my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii?1L:0L); + 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); + my_setopt(curl, CURLOPT_ERRORBUFFER, per->errorbuffer); + my_setopt(curl, CURLOPT_TIMEOUT_MS, (long)(config->timeout * 1000)); + + switch(config->httpreq) { + case HTTPREQ_SIMPLEPOST: + my_setopt_str(curl, CURLOPT_POSTFIELDS, + config->postfields); + my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, + config->postfieldsize); + break; + case HTTPREQ_MIMEPOST: + /* free previous remainders */ + curl_mime_free(config->mimepost); + config->mimepost = NULL; + result = tool2curlmime(curl, config->mimeroot, &config->mimepost); + if(result) + break; + my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost); + break; + default: + break; + } + if(result) + break; + + /* new in libcurl 7.81.0 */ + if(config->mime_options) + my_setopt(curl, CURLOPT_MIME_OPTIONS, config->mime_options); + + /* new in libcurl 7.10.6 (default is Basic) */ + if(config->authtype) + my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long)config->authtype); + + my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers); + + if(built_in_protos & (CURLPROTO_HTTP | CURLPROTO_RTSP)) { + my_setopt_str(curl, CURLOPT_REFERER, config->referer); + my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); + } + + if(built_in_protos & CURLPROTO_HTTP) { + + long postRedir = 0; + + my_setopt(curl, CURLOPT_FOLLOWLOCATION, + config->followlocation?1L:0L); + my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, + config->unrestricted_auth?1L:0L); + + my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer?1L:0L); + + /* new in libcurl 7.36.0 */ + if(config->proxyheaders) { + my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders); + my_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE); + } + + /* new in libcurl 7.5 */ + my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); + + if(config->httpversion) + my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion); + else if(curlinfo->features & CURL_VERSION_HTTP2) { + my_setopt_enum(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); + } + + /* curl 7.19.1 (the 301 version existed in 7.18.2), + 303 was added in 7.26.0 */ + 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(curl, CURLOPT_POSTREDIR, postRedir); + + /* new in libcurl 7.21.6 */ + if(config->encoding) + my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, ""); + + /* new in libcurl 7.21.6 */ + if(config->tr_encoding) + my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L); + /* new in libcurl 7.64.0 */ + my_setopt(curl, CURLOPT_HTTP09_ALLOWED, + config->http09_allowed ? 1L : 0L); + if(result) { + errorf(global, "HTTP/0.9 is not supported in this build!\n"); + return result; + } + + } /* (built_in_protos & CURLPROTO_HTTP) */ + + my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); + my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, + config->low_speed_limit); + my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time); + my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, + config->sendpersecond); + my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, + config->recvpersecond); + + if(config->use_resume) + my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from); + else + my_setopt(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 & (CURLPROTO_SCP|CURLPROTO_SFTP)) { + + /* SSH and SSL private key uses same command-line option */ + /* new in libcurl 7.16.1 */ + my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key); + /* new in libcurl 7.16.1 */ + my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey); + + /* new in libcurl 7.17.1: SSH host key md5 checking allows us + to fail if we are not talking to who we think we should */ + my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, + config->hostpubmd5); + + /* new in libcurl 7.80.0: SSH host key sha256 checking allows us + to fail if we are not talking to who we think we should */ + my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, + config->hostpubsha256); + + /* new in libcurl 7.56.0 */ + if(config->ssh_compression) + my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L); + } + + 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 = res_setopt_str(curl, CURLOPT_CAPATH, config->capath); + if(result == CURLE_NOT_BUILT_IN) { + warnf(global, "ignoring %s, not supported by libcurl\n", + capath_from_env? + "SSL_CERT_DIR environment variable":"--capath"); + } + else if(result) + break; + } + /* For the time being if --proxy-capath is not set then we use the + --capath value for it, if any. See #1257 */ + if(config->proxy_capath || config->capath) { + result = res_setopt_str(curl, CURLOPT_PROXY_CAPATH, + (config->proxy_capath ? + config->proxy_capath : + config->capath)); + if(result == CURLE_NOT_BUILT_IN) { + if(config->proxy_capath) { + warnf(global, + "ignoring --proxy-capath, not supported by libcurl\n"); + } + } + else if(result) + break; + } + + 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) /* CURLOPT_PROXY_CRLFILE default is crlfile */ + my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile); + + if(config->pinnedpubkey) + my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey); + + if(config->ssl_ec_curves) + my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves); + + if(curlinfo->features & CURL_VERSION_SSL) { + /* Check if config->cert is a PKCS#11 URI and set the + * config->cert_type if necessary */ + if(config->cert) { + if(!config->cert_type) { + if(is_pkcs11_uri(config->cert)) { + config->cert_type = strdup("ENG"); + } + } + } + + /* Check if config->key is a PKCS#11 URI and set the + * config->key_type if necessary */ + if(config->key) { + if(!config->key_type) { + if(is_pkcs11_uri(config->key)) { + config->key_type = strdup("ENG"); + } + } + } + + /* Check if config->proxy_cert is a PKCS#11 URI and set the + * config->proxy_type if necessary */ + if(config->proxy_cert) { + if(!config->proxy_cert_type) { + if(is_pkcs11_uri(config->proxy_cert)) { + config->proxy_cert_type = strdup("ENG"); + } + } + } + + /* Check if config->proxy_key is a PKCS#11 URI and set the + * config->proxy_key_type if necessary */ + if(config->proxy_key) { + if(!config->proxy_key_type) { + if(is_pkcs11_uri(config->proxy_key)) { + config->proxy_key_type = strdup("ENG"); + } + } + } + + /* In debug build of curl tool, using + * --cert loadmem=<filename>:<password> --cert-type p12 + * must do the same thing as classic: + * --cert <filename>:<password> --cert-type p12 + * but is designed to test blob */ +#if defined(CURLDEBUG) || defined(DEBUGBUILD) + if(config->cert && (strlen(config->cert) > 8) && + (memcmp(config->cert, "loadmem=",8) == 0)) { + FILE *fInCert = fopen(config->cert + 8, "rb"); + void *certdata = NULL; + long filesize = 0; + bool continue_reading = fInCert != NULL; + if(continue_reading) + continue_reading = fseek(fInCert, 0, SEEK_END) == 0; + if(continue_reading) + filesize = ftell(fInCert); + if(filesize < 0) + continue_reading = FALSE; + if(continue_reading) + continue_reading = fseek(fInCert, 0, SEEK_SET) == 0; + if(continue_reading) + certdata = malloc(((size_t)filesize) + 1); + if((!certdata) || + ((int)fread(certdata, (size_t)filesize, 1, fInCert) != 1)) + continue_reading = FALSE; + if(fInCert) + fclose(fInCert); + if((filesize > 0) && continue_reading) { + struct curl_blob structblob; + structblob.data = certdata; + structblob.len = (size_t)filesize; + structblob.flags = CURL_BLOB_COPY; + my_setopt_str(curl, CURLOPT_SSLCERT_BLOB, &structblob); + /* if test run well, we are sure we don't reuse + * original mem pointer */ + memset(certdata, 0, (size_t)filesize); + } + free(certdata); + } + else +#endif + 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); + + +#if defined(CURLDEBUG) || defined(DEBUGBUILD) + if(config->key && (strlen(config->key) > 8) && + (memcmp(config->key, "loadmem=",8) == 0)) { + FILE *fInCert = fopen(config->key + 8, "rb"); + void *certdata = NULL; + long filesize = 0; + bool continue_reading = fInCert != NULL; + if(continue_reading) + continue_reading = fseek(fInCert, 0, SEEK_END) == 0; + if(continue_reading) + filesize = ftell(fInCert); + if(filesize < 0) + continue_reading = FALSE; + if(continue_reading) + continue_reading = fseek(fInCert, 0, SEEK_SET) == 0; + if(continue_reading) + certdata = malloc(((size_t)filesize) + 1); + if((!certdata) || + ((int)fread(certdata, (size_t)filesize, 1, fInCert) != 1)) + continue_reading = FALSE; + if(fInCert) + fclose(fInCert); + if((filesize > 0) && continue_reading) { + struct curl_blob structblob; + structblob.data = certdata; + structblob.len = (size_t)filesize; + structblob.flags = CURL_BLOB_COPY; + my_setopt_str(curl, CURLOPT_SSLKEY_BLOB, &structblob); + /* if test run well, we are sure we don't reuse + * original mem pointer */ + memset(certdata, 0, (size_t)filesize); + } + free(certdata); + } + else +#endif + 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); + my_setopt_str(curl, CURLOPT_AWS_SIGV4, + config->aws_sigv4); + + if(config->insecure_ok) { + my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + } + else { + my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); + /* libcurl default is strict verifyhost -> 2L */ + /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */ + } + + if(config->doh_insecure_ok) { + my_setopt(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0L); + my_setopt(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0L); + } + + if(config->proxy_insecure_ok) { + my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L); + my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L); + } + else { + my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L); + } + + if(config->verifystatus) + my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); + + if(config->doh_verifystatus) + my_setopt(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1L); + + if(config->falsestart) + my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L); + + my_setopt_enum(curl, CURLOPT_SSLVERSION, + config->ssl_version | config->ssl_version_max); + if(config->proxy) + my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION, + config->proxy_ssl_version); + + { + long mask = + (config->ssl_allow_beast ? + CURLSSLOPT_ALLOW_BEAST : 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); + + if(mask) + my_setopt_bitmask(curl, CURLOPT_PROXY_SSL_OPTIONS, mask); + } + } + + if(config->path_as_is) + my_setopt(curl, CURLOPT_PATH_AS_IS, 1L); + + if((use_proto & (CURLPROTO_SCP|CURLPROTO_SFTP)) && + !config->insecure_ok) { + char *known = findfile(".ssh/known_hosts", FALSE); + if(known) { + /* new in curl 7.19.6 */ + result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known); + curl_free(known); + if(result == CURLE_UNKNOWN_OPTION) + /* libssh2 version older than 1.1.1 */ + result = CURLE_OK; + if(result) + break; + } + else + warnf(global, "Couldn't find a known_hosts file!"); + } + + if(config->no_body || config->remote_time) { + /* no body or use remote time */ + my_setopt(curl, CURLOPT_FILETIME, 1L); + } + + my_setopt(curl, CURLOPT_CRLF, config->crlf?1L:0L); + my_setopt_slist(curl, CURLOPT_QUOTE, config->quote); + my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote); + my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote); + + if(config->cookies) { + struct curlx_dynbuf cookies; + struct curl_slist *cl; + + /* The maximum size needs to match MAX_NAME in cookie.h */ +#define MAX_COOKIE_LINE 4096 + 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\n", MAX_COOKIE_LINE); + break; + } + } + + 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); + } + + /* new in libcurl 7.9 */ + if(config->cookiejar) + my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar); + + /* new in libcurl 7.9.7 */ + my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession?1L:0L); + + my_setopt_enum(curl, CURLOPT_TIMECONDITION, (long)config->timecond); + my_setopt(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, global->errors); + + /* three new ones in libcurl 7.3: */ + my_setopt_str(curl, CURLOPT_INTERFACE, config->iface); + my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel); + progressbarinit(&per->progressbar, config); + + if((global->progressmode == CURL_PROGRESS_BAR) && + !global->noprogress && !global->mute) { + /* we want the alternative style, then we have to implement it + ourselves! */ + my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb); + my_setopt(curl, CURLOPT_XFERINFODATA, per); + } + else if(per->uploadfile && !strcmp(per->uploadfile, ".")) { + /* when reading from stdin in non-blocking mode, we use the progress + function to unpause a busy read */ + my_setopt(curl, CURLOPT_NOPROGRESS, 0L); + my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_readbusy_cb); + my_setopt(curl, CURLOPT_XFERINFODATA, per); + } + + /* new in libcurl 7.24.0: */ + if(config->dns_servers) + my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers); + + /* new in libcurl 7.33.0: */ + 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); + + /* new in libcurl 7.6.2: */ + my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options); + + /* new in libcurl 7.7: */ + my_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, + (long)(config->connecttimeout * 1000)); + + if(config->doh_url) + my_setopt_str(curl, CURLOPT_DOH_URL, config->doh_url); + + if(config->cipher_list) + my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list); + + if(config->proxy_cipher_list) + my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, + config->proxy_cipher_list); + + if(config->cipher13_list) + my_setopt_str(curl, CURLOPT_TLS13_CIPHERS, config->cipher13_list); + + if(config->proxy_cipher13_list) + my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS, + config->proxy_cipher13_list); + + /* new in libcurl 7.9.2: */ + if(config->disable_epsv) + /* disable it */ + my_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L); + + /* new in libcurl 7.10.5 */ + if(config->disable_eprt) + /* disable it */ + my_setopt(curl, CURLOPT_FTP_USE_EPRT, 0L); + + if(global->tracetype != TRACE_NONE) { + my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb); + my_setopt(curl, CURLOPT_DEBUGDATA, config); + my_setopt(curl, CURLOPT_VERBOSE, 1L); + } + + /* new in curl 7.9.3 */ + if(config->engine) { + result = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine); + if(result) + break; + } + + /* new in curl 7.10.7, extended in 7.19.4. Modified to use + CREATE_DIR_RETRY in 7.49.0 */ + my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, + (long)(config->ftp_create_dirs? + CURLFTP_CREATE_DIR_RETRY: + CURLFTP_CREATE_DIR_NONE)); + + /* new in curl 7.10.8 */ + if(config->max_filesize) + my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE, + config->max_filesize); + + my_setopt(curl, CURLOPT_IPRESOLVE, config->ip_version); + + /* new in curl 7.15.5 */ + if(config->ftp_ssl_reqd) + my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); + + /* new in curl 7.11.0 */ + else if(config->ftp_ssl) + my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); + + /* new in curl 7.16.0 */ + else if(config->ftp_ssl_control) + my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_CONTROL); + + /* new in curl 7.16.1 */ + if(config->ftp_ssl_ccc) + my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, + (long)config->ftp_ssl_ccc_mode); + + /* new in curl 7.19.4 */ + if(config->socks5_gssapi_nec) + my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC, + config->socks5_gssapi_nec); + + /* new in curl 7.55.0 */ + if(config->socks5_auth) + my_setopt_bitmask(curl, CURLOPT_SOCKS5_AUTH, + (long)config->socks5_auth); + + /* new in curl 7.43.0 */ + if(config->proxy_service_name) + my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME, + config->proxy_service_name); + + /* new in curl 7.43.0 */ + if(config->service_name) + my_setopt_str(curl, CURLOPT_SERVICE_NAME, + config->service_name); + + /* curl 7.13.0 */ + my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account); + my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl?1L:0L); + + /* curl 7.14.2 */ + my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L); + + /* curl 7.15.1 */ + my_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long)config->ftp_filemethod); + + /* curl 7.15.2 */ + if(config->localport) { + my_setopt(curl, CURLOPT_LOCALPORT, config->localport); + my_setopt_str(curl, CURLOPT_LOCALPORTRANGE, config->localportrange); + } + + /* curl 7.15.5 */ + my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, + config->ftp_alternative_to_user); + + /* curl 7.16.0 */ + if(config->disable_sessionid) + /* disable it */ + my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); + + /* curl 7.16.2 */ + if(config->raw) { + my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L); + my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L); + } + + /* curl 7.17.1 */ + if(!config->nokeepalive) { + my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); + if(config->alivetime) { + my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime); + my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime); + } + } + else + my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L); + + /* curl 7.20.0 */ + if(config->tftp_blksize) + my_setopt(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); + + /* curl 7.69.x */ + my_setopt(curl, CURLOPT_MAIL_RCPT_ALLLOWFAILS, + config->mail_rcpt_allowfails ? 1L : 0L); + + /* curl 7.20.x */ + if(config->ftp_pret) + my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L); + + if(config->create_file_mode) + my_setopt(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->content_disposition + && (urlnode->flags & GETOUT_USEREMOTE)) + hdrcbdata->honor_cd_filename = TRUE; + else + hdrcbdata->honor_cd_filename = FALSE; + + hdrcbdata->outs = outs; + hdrcbdata->heads = heads; + hdrcbdata->etag_save = etag_save; + hdrcbdata->global = global; + hdrcbdata->config = config; + + my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb); + my_setopt(curl, CURLOPT_HEADERDATA, per); + + if(config->resolve) + /* new in 7.21.3 */ + my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve); + + if(config->connect_to) + /* new in 7.49.0 */ + my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to); + + /* new in 7.21.4 */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + 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); + } + + /* new in 7.22.0 */ + if(config->gssapi_delegation) + my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION, + config->gssapi_delegation); + + if(config->mail_auth) + my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth); + + /* new in 7.66.0 */ + if(config->sasl_authzid) + my_setopt_str(curl, CURLOPT_SASL_AUTHZID, config->sasl_authzid); + + /* new in 7.31.0 */ + if(config->sasl_ir) + my_setopt(curl, CURLOPT_SASL_IR, 1L); + + if(config->nonpn) { + my_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 0L); + } + + if(config->noalpn) { + my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); + } + + /* new in 7.40.0, abstract support added in 7.53.0 */ + 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); + } + } + + /* new in 7.45.0 */ + if(config->proto_default) + my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default); + + /* new in 7.47.0 */ + if(config->expect100timeout > 0) + my_setopt_str(curl, CURLOPT_EXPECT_100_TIMEOUT_MS, + (long)(config->expect100timeout*1000)); + + /* new in 7.48.0 */ + if(config->tftp_no_options) + my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L); + + /* new in 7.59.0 */ + if(config->happy_eyeballs_timeout_ms != CURL_HET_DEFAULT) + my_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, + config->happy_eyeballs_timeout_ms); + + /* new in 7.60.0 */ + if(config->haproxy_protocol) + my_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L); + + if(config->disallow_username_in_url) + my_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L); + + if(config->altsvc) + my_setopt_str(curl, CURLOPT_ALTSVC, config->altsvc); + + if(config->hsts) + my_setopt_str(curl, CURLOPT_HSTS, config->hsts); + + /* initialize retry vars for loop below */ + per->retry_sleep_default = (config->retry_delay) ? + config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */ + per->retry_numretries = config->req_retry; + per->retry_sleep = per->retry_sleep_default; /* ms */ + per->retrystart = tvnow(); + + state->li++; + /* Here's looping around each globbed URL */ + if(state->li >= urlnum) { + state->li = 0; + state->urlnum = 0; /* forced reglob of URLs */ + glob_cleanup(state->urls); + state->urls = NULL; + state->up++; + Curl_safefree(state->uploadfile); /* clear it to get the next */ + } + } + else { + /* Free this URL node data without destroying the + node itself nor modifying next pointer. */ + Curl_safefree(urlnode->outfile); + Curl_safefree(urlnode->infile); + urlnode->flags = 0; + glob_cleanup(state->urls); + state->urls = NULL; + state->urlnum = 0; + + Curl_safefree(state->outfiles); + Curl_safefree(state->uploadfile); + if(state->inglob) { + /* Free list of globbed upload files */ + glob_cleanup(state->inglob); + state->inglob = NULL; + } + config->state.urlnode = urlnode->next; + state->up = 0; + continue; + } + } + break; + } + Curl_safefree(state->outfiles); + + if(!*added || result) { + *added = FALSE; + single_transfer_cleanup(config); + } + return result; +} + +static long all_added; /* number of easy handles currently added */ + +/* + * add_parallel_transfers() sets 'morep' to TRUE if there are more transfers + * to add even after this call returns. sets 'addedp' to TRUE if one or more + * transfers were added. + */ +static CURLcode add_parallel_transfers(struct GlobalConfig *global, + CURLM *multi, + CURLSH *share, + bool *morep, + bool *addedp) +{ + struct per_transfer *per; + CURLcode result = CURLE_OK; + CURLMcode mcode; + bool sleeping = FALSE; + *addedp = FALSE; + *morep = FALSE; + result = create_transfer(global, share, addedp); + if(result) + return result; + for(per = transfers; per && (all_added < global->parallel_max); + per = per->next) { + bool getadded = FALSE; + if(per->added) + /* already added */ + continue; + if(per->startat && (time(NULL) < per->startat)) { + /* this is still delaying */ + sleeping = TRUE; + continue; + } + + result = pre_transfer(global, per); + if(result) + return result; + + /* parallel connect means that we don't set PIPEWAIT since pipewait + will make libcurl prefer multiplexing */ + (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT, + global->parallel_connect ? 0L : 1L); + (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per); + (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb); + (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per); + (void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L); + + mcode = curl_multi_add_handle(multi, per->curl); + if(mcode) + return CURLE_OUT_OF_MEMORY; + + result = create_transfer(global, share, &getadded); + if(result) + return result; + per->added = TRUE; + all_added++; + *addedp = TRUE; + } + *morep = (per || sleeping) ? TRUE : FALSE; + return CURLE_OK; +} + +static CURLcode parallel_transfers(struct GlobalConfig *global, + CURLSH *share) +{ + CURLM *multi; + CURLMcode mcode = CURLM_OK; + CURLcode result = CURLE_OK; + int still_running = 1; + struct timeval start = tvnow(); + bool more_transfers; + bool added_transfers; + /* wrapitup is set TRUE after a critical error occurs to end all transfers */ + bool wrapitup = FALSE; + /* wrapitup_processed is set TRUE after the per transfer abort flag is set */ + bool wrapitup_processed = FALSE; + time_t tick = time(NULL); + + multi = curl_multi_init(); + if(!multi) + return CURLE_OUT_OF_MEMORY; + + result = add_parallel_transfers(global, multi, share, + &more_transfers, &added_transfers); + if(result) { + curl_multi_cleanup(multi); + return result; + } + + while(!mcode && (still_running || more_transfers)) { + /* If stopping prematurely (eg due to a --fail-early condition) then signal + that any transfers in the multi should abort (via progress callback). */ + if(wrapitup) { + if(!still_running) + break; + if(!wrapitup_processed) { + struct per_transfer *per; + for(per = transfers; per; per = per->next) { + if(per->added) + per->abort = TRUE; + } + wrapitup_processed = TRUE; + } + } + + mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL); + if(!mcode) + mcode = curl_multi_perform(multi, &still_running); + + progress_meter(global, &start, FALSE); + + if(!mcode) { + int rc; + CURLMsg *msg; + bool checkmore = FALSE; + do { + msg = curl_multi_info_read(multi, &rc); + if(msg) { + bool retry; + long delay; + struct per_transfer *ended; + CURL *easy = msg->easy_handle; + CURLcode tres = msg->data.result; + curl_easy_getinfo(easy, CURLINFO_PRIVATE, (void *)&ended); + curl_multi_remove_handle(multi, easy); + + if(ended->abort && tres == CURLE_ABORTED_BY_CALLBACK) { + msnprintf(ended->errorbuffer, sizeof(ended->errorbuffer), + "Transfer aborted due to critical error in another transfer"); + } + tres = post_per_transfer(global, ended, tres, &retry, &delay); + progress_finalize(ended); /* before it goes away */ + all_added--; /* one fewer added */ + checkmore = TRUE; + if(retry) { + ended->added = FALSE; /* add it again */ + /* we delay retries in full integer seconds only */ + ended->startat = delay ? time(NULL) + delay/1000 : 0; + } + else { + /* result receives this transfer's error unless the transfer was + marked for abort due to a critical error in another transfer */ + if(tres && (!ended->abort || !result)) + result = tres; + if(is_fatal_error(result) || (result && global->fail_early)) + wrapitup = TRUE; + (void)del_per_transfer(ended); + } + } + } while(msg); + if(wrapitup) { + if(still_running) + continue; + else + break; + } + if(!checkmore) { + time_t tock = time(NULL); + if(tick != tock) { + checkmore = TRUE; + tick = tock; + } + } + if(checkmore) { + /* one or more transfers completed, add more! */ + CURLcode tres = add_parallel_transfers(global, multi, share, + &more_transfers, + &added_transfers); + if(tres) + result = tres; + if(added_transfers) + /* we added new ones, make sure the loop doesn't exit yet */ + still_running = 1; + } + if(is_fatal_error(result) || (result && global->fail_early)) + wrapitup = TRUE; + } + } + + (void)progress_meter(global, &start, TRUE); + + /* Make sure to return some kind of error if there was a multi problem */ + if(mcode) { + result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : + /* The other multi errors should never happen, so return + something suitably generic */ + CURLE_BAD_FUNCTION_ARGUMENT; + } + + curl_multi_cleanup(multi); + + return result; +} + +static CURLcode serial_transfers(struct GlobalConfig *global, + CURLSH *share) +{ + CURLcode returncode = CURLE_OK; + CURLcode result = CURLE_OK; + struct per_transfer *per; + bool added = FALSE; + + result = create_transfer(global, share, &added); + if(result) + return result; + if(!added) { + errorf(global, "no transfer performed\n"); + return CURLE_READ_ERROR; + } + for(per = transfers; per;) { + bool retry; + long delay_ms; + bool bailout = FALSE; + struct timeval start; + result = pre_transfer(global, per); + if(result) + break; + +#ifndef CURL_DISABLE_LIBCURL_OPTION + if(global->libcurl) { + result = easysrc_perform(); + if(result) + break; + } +#endif + start = tvnow(); +#ifdef CURLDEBUG + if(global->test_event_based) + result = curl_easy_perform_ev(per->curl); + else +#endif + result = curl_easy_perform(per->curl); + + returncode = post_per_transfer(global, per, result, &retry, &delay_ms); + if(retry) { + tool_go_sleep(delay_ms); + continue; + } + + /* Bail out upon critical errors or --fail-early */ + if(is_fatal_error(returncode) || (returncode && global->fail_early)) + bailout = TRUE; + else { + /* setup the next one just before we delete this */ + result = create_transfer(global, share, &added); + if(result) + bailout = TRUE; + } + + per = del_per_transfer(per); + + if(bailout) + break; + + if(per && global->ms_per_transfer) { + /* how long time did the most recent transfer take in number of + milliseconds */ + long milli = tvdiff(tvnow(), start); + if(milli < global->ms_per_transfer) { + notef(global, "Transfer took %ld ms, waits %ldms as set by --rate\n", + milli, global->ms_per_transfer - milli); + /* The transfer took less time than wanted. Wait a little. */ + tool_go_sleep(global->ms_per_transfer - milli); + } + } + } + if(returncode) + /* returncode errors have priority */ + result = returncode; + + if(result) + single_transfer_cleanup(global->current); + + return result; +} + +/* setup a transfer for the given config */ +static CURLcode transfer_per_config(struct GlobalConfig *global, + struct OperationConfig *config, + CURLSH *share, + bool *added) +{ + CURLcode result = CURLE_OK; + bool capath_from_env; + *added = FALSE; + + /* Check we have a url */ + if(!config->url_list || !config->url_list->url) { + helpf(global->errors, "no URL specified!\n"); + return CURLE_FAILED_INIT; + } + + /* On WIN32 we can't set the path to curl-ca-bundle.crt + * at compile time. So we look here for the file in two ways: + * 1: look at the environment variable CURL_CA_BUNDLE for a path + * 2: if #1 isn't found, use the windows API function SearchPath() + * to find it along the app's path (includes app's dir and CWD) + * + * We support the environment variable thing for non-Windows platforms + * too. Just for the sake of it. + */ + capath_from_env = false; + if(!config->cacert && + !config->capath && + (!config->insecure_ok || (config->doh_url && !config->doh_insecure_ok))) { + CURL *curltls = curl_easy_init(); + struct curl_tlssessioninfo *tls_backend_info = NULL; + + /* With the addition of CAINFO support for Schannel, this search could find + * a certificate bundle that was previously ignored. To maintain backward + * compatibility, only perform this search if not using Schannel. + */ + result = curl_easy_getinfo(curltls, CURLINFO_TLS_SSL_PTR, + &tls_backend_info); + if(result) { + curl_easy_cleanup(curltls); + return result; + } + + /* Set the CA cert locations specified in the environment. For Windows if + * no environment-specified filename is found then check for CA bundle + * default filename curl-ca-bundle.crt in the user's PATH. + * + * If Schannel is the selected SSL backend then these locations are + * ignored. We allow setting CA location for schannel only when explicitly + * specified by the user via CURLOPT_CAINFO / --cacert. + */ + if(tls_backend_info->backend != CURLSSLBACKEND_SCHANNEL) { + char *env; + env = curlx_getenv("CURL_CA_BUNDLE"); + if(env) { + config->cacert = strdup(env); + if(!config->cacert) { + curl_free(env); + curl_easy_cleanup(curltls); + errorf(global, "out of memory\n"); + return CURLE_OUT_OF_MEMORY; + } + } + else { + env = curlx_getenv("SSL_CERT_DIR"); + if(env) { + config->capath = strdup(env); + if(!config->capath) { + curl_free(env); + curl_easy_cleanup(curltls); + helpf(global->errors, "out of memory\n"); + return CURLE_OUT_OF_MEMORY; + } + capath_from_env = true; + } + else { + env = curlx_getenv("SSL_CERT_FILE"); + if(env) { + config->cacert = strdup(env); + if(!config->cacert) { + curl_free(env); + curl_easy_cleanup(curltls); + errorf(global, "out of memory\n"); + return CURLE_OUT_OF_MEMORY; + } + } + } + } + + if(env) + curl_free(env); +#ifdef WIN32 + else { + result = FindWin32CACert(config, tls_backend_info->backend, + TEXT("curl-ca-bundle.crt")); + } +#endif + } + curl_easy_cleanup(curltls); + } + + if(!result) + result = single_transfer(global, config, share, capath_from_env, added); + + return result; +} + +/* + * 'create_transfer' gets the details and sets up a new transfer if 'added' + * returns TRUE. + */ +static CURLcode create_transfer(struct GlobalConfig *global, + CURLSH *share, + bool *added) +{ + CURLcode result = CURLE_OK; + *added = FALSE; + while(global->current) { + result = transfer_per_config(global, global->current, share, added); + if(!result && !*added) { + /* when one set is drained, continue to next */ + global->current = global->current->next; + continue; + } + break; + } + return result; +} + +static CURLcode run_all_transfers(struct GlobalConfig *global, + CURLSH *share, + CURLcode result) +{ + /* Save the values of noprogress and isatty to restore them later on */ + bool orig_noprogress = global->noprogress; + bool orig_isatty = global->isatty; + struct per_transfer *per; + + /* Time to actually do the transfers */ + if(!result) { + if(global->parallel) + result = parallel_transfers(global, share); + else + result = serial_transfers(global, share); + } + + /* cleanup if there are any left */ + for(per = transfers; per;) { + bool retry; + long delay; + CURLcode result2 = post_per_transfer(global, per, result, &retry, &delay); + if(!result) + /* don't overwrite the original error */ + result = result2; + + /* Free list of given URLs */ + clean_getout(per->config); + + per = del_per_transfer(per); + } + + /* Reset the global config variables */ + global->noprogress = orig_noprogress; + global->isatty = orig_isatty; + + + return result; +} + +CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[]) +{ + CURLcode result = CURLE_OK; + char *first_arg = argc > 1 ? curlx_convert_tchar_to_UTF8(argv[1]) : NULL; + + /* Setup proper locale from environment */ +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + + /* Parse .curlrc if necessary */ + if((argc == 1) || + (first_arg && strncmp(first_arg, "-q", 2) && + !curl_strequal(first_arg, "--disable"))) { + parseconfig(NULL, global); /* ignore possible failure */ + + /* If we had no arguments then make sure a url was specified in .curlrc */ + if((argc < 2) && (!global->first->url_list)) { + helpf(global->errors, NULL); + result = CURLE_FAILED_INIT; + } + } + + curlx_unicodefree(first_arg); + + if(!result) { + /* Parse the command line arguments */ + ParameterError res = parse_args(global, argc, argv); + if(res) { + result = CURLE_OK; + + /* Check if we were asked for the help */ + if(res == PARAM_HELP_REQUESTED) + tool_help(global->help_category); + /* Check if we were asked for the manual */ + else if(res == PARAM_MANUAL_REQUESTED) + hugehelp(); + /* Check if we were asked for the version information */ + else if(res == PARAM_VERSION_INFO_REQUESTED) + tool_version_info(); + /* Check if we were asked to list the SSL engines */ + else if(res == PARAM_ENGINES_REQUESTED) + tool_list_engines(); + else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL) + result = CURLE_UNSUPPORTED_PROTOCOL; + else if(res == PARAM_READ_ERROR) + result = CURLE_READ_ERROR; + else + result = CURLE_FAILED_INIT; + } + else { +#ifndef CURL_DISABLE_LIBCURL_OPTION + if(global->libcurl) { + /* Initialise the libcurl source output */ + result = easysrc_init(); + } +#endif + + /* Perform the main operations */ + if(!result) { + size_t count = 0; + struct OperationConfig *operation = global->first; + CURLSH *share = curl_share_init(); + if(!share) { +#ifndef CURL_DISABLE_LIBCURL_OPTION + if(global->libcurl) { + /* Cleanup the libcurl source output */ + easysrc_cleanup(); + } +#endif + return CURLE_OUT_OF_MEMORY; + } + + curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); + curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); + curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); + curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); + curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL); + + /* Get the required arguments for each operation */ + do { + result = get_args(operation, count++); + + operation = operation->next; + } while(!result && operation); + + /* Set the current operation pointer */ + global->current = global->first; + + /* now run! */ + result = run_all_transfers(global, share, result); + + curl_share_cleanup(share); +#ifndef CURL_DISABLE_LIBCURL_OPTION + if(global->libcurl) { + /* Cleanup the libcurl source output */ + easysrc_cleanup(); + + /* Dump the libcurl code if previously enabled */ + dumpeasysrc(global); + } +#endif + } + else + errorf(global, "out of memory\n"); + } + } + + return result; +} diff --git a/contrib/libs/curl/src/tool_operate.h b/contrib/libs/curl/src/tool_operate.h new file mode 100644 index 0000000000..a779239478 --- /dev/null +++ b/contrib/libs/curl/src/tool_operate.h @@ -0,0 +1,81 @@ +#ifndef HEADER_CURL_TOOL_OPERATE_H +#define HEADER_CURL_TOOL_OPERATE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#include "tool_cb_hdr.h" +#include "tool_cb_prg.h" +#include "tool_sdecls.h" + +struct per_transfer { + /* double linked */ + struct per_transfer *next; + struct per_transfer *prev; + struct OperationConfig *config; /* for this transfer */ + CURL *curl; + long retry_numretries; + long retry_sleep_default; + long retry_sleep; + struct timeval retrystart; + char *this_url; + unsigned int urlnum; /* the index of the given URL */ + char *outfile; + bool infdopen; /* TRUE if infd needs closing */ + int infd; + bool noprogress; + struct ProgressData progressbar; + struct OutStruct outs; + struct OutStruct heads; + struct OutStruct etag_save; + struct InStruct input; + struct HdrCbData hdrcbdata; + long num_headers; + bool was_last_header_empty; + char errorbuffer[CURL_ERROR_SIZE]; + + bool added; /* set TRUE when added to the multi handle */ + time_t startat; /* when doing parallel transfers, this is a retry transfer + that has been set to sleep until this time before it + should get started (again) */ + bool abort; /* when doing parallel transfers and this is TRUE then a critical + error (eg --fail-early) has occurred in another transfer and + this transfer will be aborted in the progress callback */ + + /* for parallel progress bar */ + curl_off_t dltotal; + curl_off_t dlnow; + curl_off_t ultotal; + curl_off_t ulnow; + bool dltotal_added; /* if the total has been added from this */ + bool ultotal_added; + + /* NULL or malloced */ + char *uploadfile; +}; + +CURLcode operate(struct GlobalConfig *config, int argc, argv_item_t argv[]); + +extern struct per_transfer *transfers; /* first node */ + +#endif /* HEADER_CURL_TOOL_OPERATE_H */ diff --git a/contrib/libs/curl/src/tool_operhlp.c b/contrib/libs/curl/src/tool_operhlp.c new file mode 100644 index 0000000000..014444219c --- /dev/null +++ b/contrib/libs/curl/src/tool_operhlp.c @@ -0,0 +1,197 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_doswin.h" +#include "tool_operhlp.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void clean_getout(struct OperationConfig *config) +{ + if(config) { + struct getout *next; + struct getout *node = config->url_list; + + while(node) { + next = node->next; + Curl_safefree(node->url); + Curl_safefree(node->outfile); + Curl_safefree(node->infile); + Curl_safefree(node); + node = next; + } + config->url_list = NULL; + } +} + +bool output_expected(const char *url, const char *uploadfile) +{ + if(!uploadfile) + return TRUE; /* download */ + if(checkprefix("http://", url) || checkprefix("https://", url)) + return TRUE; /* HTTP(S) upload */ + + return FALSE; /* non-HTTP upload, probably no output should be expected */ +} + +bool stdin_upload(const char *uploadfile) +{ + return (!strcmp(uploadfile, "-") || + !strcmp(uploadfile, ".")) ? TRUE : FALSE; +} + +/* + * Adds the file name to the URL if it doesn't already have one. + * url will be freed before return if the returned pointer is different + */ +char *add_file_name_to_url(char *url, const char *filename) +{ + /* If no file name part is given in the URL, we add this file name */ + char *ptr = strstr(url, "://"); + CURL *curl = curl_easy_init(); /* for url escaping */ + if(!curl) + return NULL; /* error! */ + if(ptr) + ptr += 3; + else + ptr = url; + ptr = strrchr(ptr, '/'); + if(!ptr || !*++ptr) { + /* The URL has no file name part, add the local file name. In order + to be able to do so, we have to create a new URL in another + buffer.*/ + + /* We only want the part of the local path that is on the right + side of the rightmost slash and backslash. */ + const char *filep = strrchr(filename, '/'); + char *file2 = strrchr(filep?filep:filename, '\\'); + char *encfile; + + if(file2) + filep = file2 + 1; + else if(filep) + filep++; + else + filep = filename; + + /* URL encode the file name */ + encfile = curl_easy_escape(curl, filep, 0 /* use strlen */); + if(encfile) { + char *urlbuffer; + if(ptr) + /* there is a trailing slash on the URL */ + urlbuffer = aprintf("%s%s", url, encfile); + else + /* there is no trailing slash on the URL */ + urlbuffer = aprintf("%s/%s", url, encfile); + + curl_free(encfile); + + if(!urlbuffer) { + url = NULL; + goto end; + } + + Curl_safefree(url); + url = urlbuffer; /* use our new URL instead! */ + } + } + end: + curl_easy_cleanup(curl); + return url; +} + +/* Extracts the name portion of the URL. + * Returns a pointer to a heap-allocated string or NULL if + * no name part, at location indicated by first argument. + */ +CURLcode get_url_file_name(char **filename, const char *url) +{ + const char *pc, *pc2; + + *filename = NULL; + + /* Find and get the remote file name */ + pc = strstr(url, "://"); + if(pc) + pc += 3; + else + pc = url; + + pc2 = strrchr(pc, '\\'); + pc = strrchr(pc, '/'); + if(pc2 && (!pc || pc < pc2)) + pc = pc2; + + if(pc) + /* duplicate the string beyond the slash */ + pc++; + else + /* no slash => empty string */ + pc = ""; + + *filename = strdup(pc); + if(!*filename) + return CURLE_OUT_OF_MEMORY; + +#if defined(MSDOS) || defined(WIN32) + { + char *sanitized; + SANITIZEcode sc = sanitize_file_name(&sanitized, *filename, 0); + Curl_safefree(*filename); + if(sc) + return CURLE_URL_MALFORMAT; + *filename = sanitized; + } +#endif /* MSDOS || WIN32 */ + + /* in case we built debug enabled, we allow an environment variable + * named CURL_TESTDIR to prefix the given file name to put it into a + * specific directory + */ +#ifdef DEBUGBUILD + { + char *tdir = curlx_getenv("CURL_TESTDIR"); + if(tdir) { + char buffer[512]; /* suitably large */ + msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, *filename); + Curl_safefree(*filename); + *filename = strdup(buffer); /* clone the buffer */ + curl_free(tdir); + if(!*filename) + return CURLE_OUT_OF_MEMORY; + } + } +#endif + + return CURLE_OK; +} diff --git a/contrib/libs/curl/src/tool_operhlp.h b/contrib/libs/curl/src/tool_operhlp.h new file mode 100644 index 0000000000..c48d7eca64 --- /dev/null +++ b/contrib/libs/curl/src/tool_operhlp.h @@ -0,0 +1,40 @@ +#ifndef HEADER_CURL_TOOL_OPERHLP_H +#define HEADER_CURL_TOOL_OPERHLP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +struct OperationConfig; + +void clean_getout(struct OperationConfig *config); + +bool output_expected(const char *url, const char *uploadfile); + +bool stdin_upload(const char *uploadfile); + +char *add_file_name_to_url(char *url, const char *filename); + +CURLcode get_url_file_name(char **filename, const char *url); + +#endif /* HEADER_CURL_TOOL_OPERHLP_H */ diff --git a/contrib/libs/curl/src/tool_panykey.c b/contrib/libs/curl/src/tool_panykey.c new file mode 100644 index 0000000000..dce4f404c7 --- /dev/null +++ b/contrib/libs/curl/src/tool_panykey.c @@ -0,0 +1,47 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(NETWARE) + +#ifdef NETWARE +# ifdef __NOVELL_LIBC__ +# include <screen.h> +# else +# error #include <nwconio.h> +# endif +#endif + +#include "tool_panykey.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void tool_pressanykey(void) +{ +#if defined(NETWARE) + pressanykey(); +#endif +} + +#endif /* NETWARE */ diff --git a/contrib/libs/curl/src/tool_panykey.h b/contrib/libs/curl/src/tool_panykey.h new file mode 100644 index 0000000000..c5cc322606 --- /dev/null +++ b/contrib/libs/curl/src/tool_panykey.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_TOOL_PANYKEY_H +#define HEADER_CURL_TOOL_PANYKEY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#if defined(NETWARE) +void tool_pressanykey(void); +#else +#define tool_pressanykey() Curl_nop_stmt +#endif + +#endif /* HEADER_CURL_TOOL_PANYKEY_H */ diff --git a/contrib/libs/curl/src/tool_paramhlp.c b/contrib/libs/curl/src/tool_paramhlp.c new file mode 100644 index 0000000000..9306498e23 --- /dev/null +++ b/contrib/libs/curl/src/tool_paramhlp.c @@ -0,0 +1,658 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "strcase.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_getparam.h" +#include "tool_getpass.h" +#include "tool_msgs.h" +#include "tool_paramhlp.h" +#include "tool_version.h" +#include "dynbuf.h" + +#include "memdebug.h" /* keep this as LAST include */ + +struct getout *new_getout(struct OperationConfig *config) +{ + struct getout *node = calloc(1, sizeof(struct getout)); + struct getout *last = config->url_last; + if(node) { + static int outnum = 0; + + /* append this new node last in the list */ + if(last) + last->next = node; + else + config->url_list = node; /* first node */ + + /* move the last pointer */ + config->url_last = node; + + node->flags = config->default_node_flags; + node->num = outnum++; + } + return node; +} + +#define MAX_FILE2STRING (256*1024*1024) /* big enough ? */ + +ParameterError file2string(char **bufp, FILE *file) +{ + struct curlx_dynbuf dyn; + curlx_dyn_init(&dyn, MAX_FILE2STRING); + if(file) { + char buffer[256]; + + while(fgets(buffer, sizeof(buffer), file)) { + char *ptr = strchr(buffer, '\r'); + if(ptr) + *ptr = '\0'; + ptr = strchr(buffer, '\n'); + if(ptr) + *ptr = '\0'; + if(curlx_dyn_add(&dyn, buffer)) + return PARAM_NO_MEM; + } + } + *bufp = curlx_dyn_ptr(&dyn); + return PARAM_OK; +} + +#define MAX_FILE2MEMORY (1024*1024*1024) /* big enough ? */ + +ParameterError file2memory(char **bufp, size_t *size, FILE *file) +{ + if(file) { + size_t nread; + struct curlx_dynbuf dyn; + curlx_dyn_init(&dyn, MAX_FILE2MEMORY); + do { + char buffer[4096]; + nread = fread(buffer, 1, sizeof(buffer), file); + if(ferror(file)) { + curlx_dyn_free(&dyn); + *size = 0; + *bufp = NULL; + return PARAM_READ_ERROR; + } + if(nread) + if(curlx_dyn_addn(&dyn, buffer, nread)) + return PARAM_NO_MEM; + } while(!feof(file)); + *size = curlx_dyn_len(&dyn); + *bufp = curlx_dyn_ptr(&dyn); + } + else { + *size = 0; + *bufp = NULL; + } + return PARAM_OK; +} + +/* + * Parse the string and write the long in the given address. Return PARAM_OK + * on success, otherwise a parameter specific error enum. + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ +static ParameterError getnum(long *val, const char *str, int base) +{ + if(str) { + char *endptr = NULL; + long num; + errno = 0; + num = strtol(str, &endptr, base); + if(errno == ERANGE) + return PARAM_NUMBER_TOO_LARGE; + if((endptr != str) && (endptr == str + strlen(str))) { + *val = num; + return PARAM_OK; /* Ok */ + } + } + return PARAM_BAD_NUMERIC; /* badness */ +} + +ParameterError str2num(long *val, const char *str) +{ + return getnum(val, str, 10); +} + +ParameterError oct2nummax(long *val, const char *str, long max) +{ + ParameterError result = getnum(val, str, 8); + if(result != PARAM_OK) + return result; + else if(*val > max) + return PARAM_NUMBER_TOO_LARGE; + else if(*val < 0) + return PARAM_NEGATIVE_NUMERIC; + + return PARAM_OK; +} + +/* + * Parse the string and write the long in the given address. Return PARAM_OK + * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS! + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ + +ParameterError str2unum(long *val, const char *str) +{ + ParameterError result = getnum(val, str, 10); + if(result != PARAM_OK) + return result; + if(*val < 0) + return PARAM_NEGATIVE_NUMERIC; + + return PARAM_OK; +} + +/* + * Parse the string and write the long in the given address if it is below the + * maximum allowed value. Return PARAM_OK on success, otherwise a parameter + * error enum. ONLY ACCEPTS POSITIVE NUMBERS! + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ + +ParameterError str2unummax(long *val, const char *str, long max) +{ + ParameterError result = str2unum(val, str); + if(result != PARAM_OK) + return result; + if(*val > max) + return PARAM_NUMBER_TOO_LARGE; + + return PARAM_OK; +} + + +/* + * Parse the string and write the double in the given address. Return PARAM_OK + * on success, otherwise a parameter specific error enum. + * + * The 'max' argument is the maximum value allowed, as the numbers are often + * multiplied when later used. + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ + +static ParameterError str2double(double *val, const char *str, long max) +{ + if(str) { + char *endptr; + double num; + errno = 0; + num = strtod(str, &endptr); + if(errno == ERANGE) + return PARAM_NUMBER_TOO_LARGE; + if(num > max) { + /* too large */ + return PARAM_NUMBER_TOO_LARGE; + } + if((endptr != str) && (endptr == str + strlen(str))) { + *val = num; + return PARAM_OK; /* Ok */ + } + } + return PARAM_BAD_NUMERIC; /* badness */ +} + +/* + * Parse the string and write the double in the given address. Return PARAM_OK + * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS! + * + * The 'max' argument is the maximum value allowed, as the numbers are often + * multiplied when later used. + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ + +ParameterError str2udouble(double *valp, const char *str, long max) +{ + double value; + ParameterError result = str2double(&value, str, max); + if(result != PARAM_OK) + return result; + if(value < 0) + return PARAM_NEGATIVE_NUMERIC; + + *valp = value; + return PARAM_OK; +} + +/* + * Parse the string and provide an allocated libcurl compatible protocol + * string output. Return non-zero on failure, zero on success. + * + * The string is a list of protocols + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ + +ParameterError proto2num(struct OperationConfig *config, + unsigned int val, char **ostr, const char *str) +{ + char *buffer; + const char *sep = ","; + char *token; + char obuf[256] = ""; + size_t olen = sizeof(obuf); + char *optr; + struct sprotos const *pp; + + static struct sprotos { + const char *name; + unsigned int bit; + } const protos[] = { + { "all", (unsigned int)CURLPROTO_ALL }, + { "http", CURLPROTO_HTTP }, + { "https", CURLPROTO_HTTPS }, + { "ftp", CURLPROTO_FTP }, + { "ftps", CURLPROTO_FTPS }, + { "scp", CURLPROTO_SCP }, + { "sftp", CURLPROTO_SFTP }, + { "telnet", CURLPROTO_TELNET }, + { "ldap", CURLPROTO_LDAP }, + { "ldaps", CURLPROTO_LDAPS }, + { "mqtt", CURLPROTO_MQTT }, + { "dict", CURLPROTO_DICT }, + { "file", CURLPROTO_FILE }, + { "tftp", CURLPROTO_TFTP }, + { "imap", CURLPROTO_IMAP }, + { "imaps", CURLPROTO_IMAPS }, + { "pop3", CURLPROTO_POP3 }, + { "pop3s", CURLPROTO_POP3S }, + { "smtp", CURLPROTO_SMTP }, + { "smtps", CURLPROTO_SMTPS }, + { "rtsp", CURLPROTO_RTSP }, + { "gopher", CURLPROTO_GOPHER }, + { "gophers", CURLPROTO_GOPHERS }, + { "smb", CURLPROTO_SMB }, + { "smbs", CURLPROTO_SMBS }, + { NULL, 0 } + }; + + if(!str) + return PARAM_OPTION_AMBIGUOUS; + + buffer = strdup(str); /* because strtok corrupts it */ + if(!buffer) + return PARAM_NO_MEM; + + /* Allow strtok() here since this isn't used threaded */ + /* !checksrc! disable BANNEDFUNC 2 */ + for(token = strtok(buffer, sep); + token; + token = strtok(NULL, sep)) { + enum e_action { allow, deny, set } action = allow; + + /* Process token modifiers */ + while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */ + switch (*token++) { + case '=': + action = set; + break; + case '-': + action = deny; + break; + case '+': + action = allow; + break; + default: /* Includes case of terminating NULL */ + Curl_safefree(buffer); + return PARAM_BAD_USE; + } + } + + for(pp = protos; pp->name; pp++) { + if(curl_strequal(token, pp->name)) { + switch(action) { + case deny: + val &= ~(pp->bit); + break; + case allow: + val |= pp->bit; + break; + case set: + val = pp->bit; + break; + } + break; + } + } + + if(!(pp->name)) { /* unknown protocol */ + /* If they have specified only this protocol, we say treat it as + if no protocols are allowed */ + if(action == set) + val = 0; + warnf(config->global, "unrecognized protocol '%s'\n", token); + } + } + Curl_safefree(buffer); + + optr = obuf; + for(pp = &protos[1]; pp->name; pp++) { + if(val & pp->bit) { + size_t n = msnprintf(optr, olen, "%s%s", + olen != sizeof(obuf) ? "," : "", + pp->name); + olen -= n; + optr += n; + } + } + *ostr = strdup(obuf); + + return *ostr ? PARAM_OK : PARAM_NO_MEM; +} + +/** + * Check if the given string is a protocol supported by libcurl + * + * @param str the protocol name + * @return PARAM_OK protocol supported + * @return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL protocol not supported + * @return PARAM_REQUIRES_PARAMETER missing parameter + */ +ParameterError check_protocol(const char *str) +{ + const char * const *pp; + const curl_version_info_data *curlinfo = curl_version_info(CURLVERSION_NOW); + if(!str) + return PARAM_REQUIRES_PARAMETER; + for(pp = curlinfo->protocols; *pp; pp++) { + if(curl_strequal(*pp, str)) + return PARAM_OK; + } + return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL; +} + +/** + * Parses the given string looking for an offset (which may be a + * larger-than-integer value). The offset CANNOT be negative! + * + * @param val the offset to populate + * @param str the buffer containing the offset + * @return PARAM_OK if successful, a parameter specific error enum if failure. + */ +ParameterError str2offset(curl_off_t *val, const char *str) +{ + char *endptr; + if(str[0] == '-') + /* offsets aren't negative, this indicates weird input */ + return PARAM_NEGATIVE_NUMERIC; + +#if(SIZEOF_CURL_OFF_T > SIZEOF_LONG) + { + CURLofft offt = curlx_strtoofft(str, &endptr, 0, val); + if(CURL_OFFT_FLOW == offt) + return PARAM_NUMBER_TOO_LARGE; + else if(CURL_OFFT_INVAL == offt) + return PARAM_BAD_NUMERIC; + } +#else + errno = 0; + *val = strtol(str, &endptr, 0); + if((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE) + return PARAM_NUMBER_TOO_LARGE; +#endif + if((endptr != str) && (endptr == str + strlen(str))) + return PARAM_OK; + + return PARAM_BAD_NUMERIC; +} + +#define MAX_USERPWDLENGTH (100*1024) +static CURLcode checkpasswd(const char *kind, /* for what purpose */ + const size_t i, /* operation index */ + const bool last, /* TRUE if last operation */ + char **userpwd) /* pointer to allocated string */ +{ + char *psep; + char *osep; + + if(!*userpwd) + return CURLE_OK; + + /* Attempt to find the password separator */ + psep = strchr(*userpwd, ':'); + + /* Attempt to find the options separator */ + osep = strchr(*userpwd, ';'); + + if(!psep && **userpwd != ';') { + /* no password present, prompt for one */ + char passwd[2048] = ""; + char prompt[256]; + struct curlx_dynbuf dyn; + + curlx_dyn_init(&dyn, MAX_USERPWDLENGTH); + if(osep) + *osep = '\0'; + + /* build a nice-looking prompt */ + if(!i && last) + curlx_msnprintf(prompt, sizeof(prompt), + "Enter %s password for user '%s':", + kind, *userpwd); + else + curlx_msnprintf(prompt, sizeof(prompt), + "Enter %s password for user '%s' on URL #%zu:", + kind, *userpwd, i + 1); + + /* get password */ + getpass_r(prompt, passwd, sizeof(passwd)); + if(osep) + *osep = ';'; + + if(curlx_dyn_addf(&dyn, "%s:%s", *userpwd, passwd)) + return CURLE_OUT_OF_MEMORY; + + /* return the new string */ + free(*userpwd); + *userpwd = curlx_dyn_ptr(&dyn); + } + + return CURLE_OK; +} + +ParameterError add2list(struct curl_slist **list, const char *ptr) +{ + struct curl_slist *newlist = curl_slist_append(*list, ptr); + if(newlist) + *list = newlist; + else + return PARAM_NO_MEM; + + return PARAM_OK; +} + +int ftpfilemethod(struct OperationConfig *config, const char *str) +{ + if(curl_strequal("singlecwd", str)) + return CURLFTPMETHOD_SINGLECWD; + if(curl_strequal("nocwd", str)) + return CURLFTPMETHOD_NOCWD; + if(curl_strequal("multicwd", str)) + return CURLFTPMETHOD_MULTICWD; + + warnf(config->global, "unrecognized ftp file method '%s', using default\n", + str); + + return CURLFTPMETHOD_MULTICWD; +} + +int ftpcccmethod(struct OperationConfig *config, const char *str) +{ + if(curl_strequal("passive", str)) + return CURLFTPSSL_CCC_PASSIVE; + if(curl_strequal("active", str)) + return CURLFTPSSL_CCC_ACTIVE; + + warnf(config->global, "unrecognized ftp CCC method '%s', using default\n", + str); + + return CURLFTPSSL_CCC_PASSIVE; +} + +long delegation(struct OperationConfig *config, const char *str) +{ + if(curl_strequal("none", str)) + return CURLGSSAPI_DELEGATION_NONE; + if(curl_strequal("policy", str)) + return CURLGSSAPI_DELEGATION_POLICY_FLAG; + if(curl_strequal("always", str)) + return CURLGSSAPI_DELEGATION_FLAG; + + warnf(config->global, "unrecognized delegation method '%s', using none\n", + str); + + return CURLGSSAPI_DELEGATION_NONE; +} + +/* + * my_useragent: returns allocated string with default user agent + */ +static char *my_useragent(void) +{ + return strdup(CURL_NAME "/" CURL_VERSION); +} + +#define isheadersep(x) ((((x)==':') || ((x)==';'))) + +/* + * inlist() returns true if the given 'checkfor' header is present in the + * header list. + */ +static bool inlist(const struct curl_slist *head, + const char *checkfor) +{ + size_t thislen = strlen(checkfor); + DEBUGASSERT(thislen); + DEBUGASSERT(checkfor[thislen-1] != ':'); + + for(; head; head = head->next) { + if(curl_strnequal(head->data, checkfor, thislen) && + isheadersep(head->data[thislen]) ) + return TRUE; + } + + return FALSE; +} + +CURLcode get_args(struct OperationConfig *config, const size_t i) +{ + CURLcode result = CURLE_OK; + bool last = (config->next ? FALSE : TRUE); + + if(config->jsoned) { + ParameterError err = PARAM_OK; + /* --json also implies json Content-Type: and Accept: headers - if + they are not set with -H */ + if(!inlist(config->headers, "Content-Type")) + err = add2list(&config->headers, "Content-Type: application/json"); + if(!err && !inlist(config->headers, "Accept")) + err = add2list(&config->headers, "Accept: application/json"); + if(err) + return CURLE_OUT_OF_MEMORY; + } + + /* Check we have a password for the given host user */ + if(config->userpwd && !config->oauth_bearer) { + result = checkpasswd("host", i, last, &config->userpwd); + if(result) + return result; + } + + /* Check we have a password for the given proxy user */ + if(config->proxyuserpwd) { + result = checkpasswd("proxy", i, last, &config->proxyuserpwd); + if(result) + return result; + } + + /* Check we have a user agent */ + if(!config->useragent) { + config->useragent = my_useragent(); + if(!config->useragent) { + errorf(config->global, "out of memory\n"); + result = CURLE_OUT_OF_MEMORY; + } + } + + return result; +} + +/* + * Parse the string and modify ssl_version in the val argument. Return PARAM_OK + * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS! + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ + +ParameterError str2tls_max(long *val, const char *str) +{ + static struct s_tls_max { + const char *tls_max_str; + long tls_max; + } const tls_max_array[] = { + { "default", CURL_SSLVERSION_MAX_DEFAULT }, + { "1.0", CURL_SSLVERSION_MAX_TLSv1_0 }, + { "1.1", CURL_SSLVERSION_MAX_TLSv1_1 }, + { "1.2", CURL_SSLVERSION_MAX_TLSv1_2 }, + { "1.3", CURL_SSLVERSION_MAX_TLSv1_3 } + }; + size_t i = 0; + if(!str) + return PARAM_REQUIRES_PARAMETER; + for(i = 0; i < sizeof(tls_max_array)/sizeof(tls_max_array[0]); i++) { + if(!strcmp(str, tls_max_array[i].tls_max_str)) { + *val = tls_max_array[i].tls_max; + return PARAM_OK; + } + } + return PARAM_BAD_USE; +} diff --git a/contrib/libs/curl/src/tool_paramhlp.h b/contrib/libs/curl/src/tool_paramhlp.h new file mode 100644 index 0000000000..6d9451f1d9 --- /dev/null +++ b/contrib/libs/curl/src/tool_paramhlp.h @@ -0,0 +1,60 @@ +#ifndef HEADER_CURL_TOOL_PARAMHLP_H +#define HEADER_CURL_TOOL_PARAMHLP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +struct getout *new_getout(struct OperationConfig *config); + +ParameterError file2string(char **bufp, FILE *file); + +ParameterError file2memory(char **bufp, size_t *size, FILE *file); + +ParameterError str2num(long *val, const char *str); +ParameterError str2unum(long *val, const char *str); +ParameterError oct2nummax(long *val, const char *str, long max); +ParameterError str2unummax(long *val, const char *str, long max); +ParameterError str2udouble(double *val, const char *str, long max); + +ParameterError proto2num(struct OperationConfig *config, + unsigned int val, char **obuf, + const char *str); + +ParameterError check_protocol(const char *str); + +ParameterError str2offset(curl_off_t *val, const char *str); + +CURLcode get_args(struct OperationConfig *config, const size_t i); + +ParameterError add2list(struct curl_slist **list, const char *ptr); + +int ftpfilemethod(struct OperationConfig *config, const char *str); + +int ftpcccmethod(struct OperationConfig *config, const char *str); + +long delegation(struct OperationConfig *config, const char *str); + +ParameterError str2tls_max(long *val, const char *str); + +#endif /* HEADER_CURL_TOOL_PARAMHLP_H */ diff --git a/contrib/libs/curl/src/tool_parsecfg.c b/contrib/libs/curl/src/tool_parsecfg.c new file mode 100644 index 0000000000..a166757f86 --- /dev/null +++ b/contrib/libs/curl/src/tool_parsecfg.c @@ -0,0 +1,351 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_getparam.h" +#include "tool_helpers.h" +#include "tool_findfile.h" +#include "tool_msgs.h" +#include "tool_parsecfg.h" +#include "dynbuf.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* only acknowledge colon or equals as separators if the option was not + specified with an initial dash! */ +#define ISSEP(x,dash) (!dash && (((x) == '=') || ((x) == ':'))) + +static const char *unslashquote(const char *line, char *param); + +#define MAX_CONFIG_LINE_LENGTH (100*1024) +static bool my_get_line(FILE *fp, struct curlx_dynbuf *, bool *error); + +#ifdef WIN32 +static FILE *execpath(const char *filename, char **pathp) +{ + static char filebuffer[512]; + /* Get the filename of our executable. GetModuleFileName is already declared + * via inclusions done in setup header file. We assume that we are using + * the ASCII version here. + */ + unsigned long len = GetModuleFileNameA(0, filebuffer, sizeof(filebuffer)); + if(len > 0 && len < sizeof(filebuffer)) { + /* We got a valid filename - get the directory part */ + char *lastdirchar = strrchr(filebuffer, '\\'); + if(lastdirchar) { + size_t remaining; + *lastdirchar = 0; + /* If we have enough space, build the RC filename */ + remaining = sizeof(filebuffer) - strlen(filebuffer); + if(strlen(filename) < remaining - 1) { + FILE *f; + msnprintf(lastdirchar, remaining, "%s%s", DIR_CHAR, filename); + *pathp = filebuffer; + f = fopen(filebuffer, FOPEN_READTEXT); + return f; + } + } + } + + return NULL; +} +#endif + + +/* return 0 on everything-is-fine, and non-zero otherwise */ +int parseconfig(const char *filename, struct GlobalConfig *global) +{ + FILE *file = NULL; + bool usedarg = FALSE; + int rc = 0; + struct OperationConfig *operation = global->last; + char *pathalloc = NULL; + + if(!filename) { + /* NULL means load .curlrc from homedir! */ + char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE); + if(curlrc) { + file = fopen(curlrc, FOPEN_READTEXT); + if(!file) { + free(curlrc); + return 1; + } + filename = pathalloc = curlrc; + } +#ifdef WIN32 /* Windows */ + else { + char *fullp; + /* check for .curlrc then _curlrc in the dir of the executable */ + file = execpath(".curlrc", &fullp); + if(!file) + file = execpath("_curlrc", &fullp); + if(file) + /* this is the filename we read from */ + filename = fullp; + } +#endif + } + else { + if(strcmp(filename, "-")) + file = fopen(filename, FOPEN_READTEXT); + else + file = stdin; + } + + if(file) { + char *line; + char *option; + char *param; + int lineno = 0; + bool dashed_option; + struct curlx_dynbuf buf; + bool fileerror; + curlx_dyn_init(&buf, MAX_CONFIG_LINE_LENGTH); + DEBUGASSERT(filename); + + while(my_get_line(file, &buf, &fileerror)) { + int res; + bool alloced_param = FALSE; + lineno++; + line = curlx_dyn_ptr(&buf); + if(!line) { + rc = 1; /* out of memory */ + break; + } + + /* line with # in the first non-blank column is a comment! */ + while(*line && ISSPACE(*line)) + line++; + + switch(*line) { + case '#': + case '/': + case '\r': + case '\n': + case '*': + case '\0': + curlx_dyn_reset(&buf); + continue; + } + + /* the option keywords starts here */ + option = line; + + /* the option starts with a dash? */ + dashed_option = option[0]=='-'?TRUE:FALSE; + + while(*line && !ISSPACE(*line) && !ISSEP(*line, dashed_option)) + line++; + /* ... and has ended here */ + + if(*line) + *line++ = '\0'; /* null-terminate, we have a local copy of the data */ + +#ifdef DEBUG_CONFIG + fprintf(stderr, "GOT: %s\n", option); +#endif + + /* pass spaces and separator(s) */ + while(*line && (ISSPACE(*line) || ISSEP(*line, dashed_option))) + line++; + + /* the parameter starts here (unless quoted) */ + if(*line == '\"') { + /* quoted parameter, do the quote dance */ + line++; + param = malloc(strlen(line) + 1); /* parameter */ + if(!param) { + /* out of memory */ + rc = 1; + break; + } + alloced_param = TRUE; + (void)unslashquote(line, param); + } + else { + param = line; /* parameter starts here */ + while(*line && !ISSPACE(*line)) + line++; + + if(*line) { + *line = '\0'; /* null-terminate */ + + /* to detect mistakes better, see if there's data following */ + line++; + /* pass all spaces */ + while(*line && ISSPACE(*line)) + line++; + + switch(*line) { + case '\0': + case '\r': + case '\n': + case '#': /* comment */ + break; + default: + warnf(operation->global, "%s:%d: warning: '%s' uses unquoted " + "whitespace in the line that may cause side-effects!\n", + filename, lineno, option); + } + } + if(!*param) + /* do this so getparameter can check for required parameters. + Otherwise it always thinks there's a parameter. */ + param = NULL; + } + +#ifdef DEBUG_CONFIG + fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); +#endif + res = getparameter(option, param, &usedarg, global, operation); + operation = global->last; + + if(!res && param && *param && !usedarg) + /* we passed in a parameter that wasn't used! */ + res = PARAM_GOT_EXTRA_PARAMETER; + + if(res == PARAM_NEXT_OPERATION) { + if(operation->url_list && operation->url_list->url) { + /* Allocate the next config */ + operation->next = malloc(sizeof(struct OperationConfig)); + if(operation->next) { + /* Initialise the newly created config */ + config_init(operation->next); + + /* Set the global config pointer */ + operation->next->global = global; + + /* Update the last operation pointer */ + global->last = operation->next; + + /* Move onto the new config */ + operation->next->prev = operation; + operation = operation->next; + } + else + res = PARAM_NO_MEM; + } + } + + if(res != PARAM_OK && res != PARAM_NEXT_OPERATION) { + /* the help request isn't really an error */ + if(!strcmp(filename, "-")) { + filename = "<stdin>"; + } + if(res != PARAM_HELP_REQUESTED && + res != PARAM_MANUAL_REQUESTED && + res != PARAM_VERSION_INFO_REQUESTED && + res != PARAM_ENGINES_REQUESTED) { + const char *reason = param2text(res); + warnf(operation->global, "%s:%d: warning: '%s' %s\n", + filename, lineno, option, reason); + } + } + + if(alloced_param) + Curl_safefree(param); + + curlx_dyn_reset(&buf); + } + curlx_dyn_free(&buf); + if(file != stdin) + fclose(file); + if(fileerror) + rc = 1; + } + else + rc = 1; /* couldn't open the file */ + + free(pathalloc); + return rc; +} + +/* + * Copies the string from line to the buffer at param, unquoting + * backslash-quoted characters and NUL-terminating the output string. + * Stops at the first non-backslash-quoted double quote character or the + * end of the input string. param must be at least as long as the input + * string. Returns the pointer after the last handled input character. + */ +static const char *unslashquote(const char *line, char *param) +{ + while(*line && (*line != '\"')) { + if(*line == '\\') { + char out; + line++; + + /* default is to output the letter after the backslash */ + switch(out = *line) { + case '\0': + continue; /* this'll break out of the loop */ + case 't': + out = '\t'; + break; + case 'n': + out = '\n'; + break; + case 'r': + out = '\r'; + break; + case 'v': + out = '\v'; + break; + } + *param++ = out; + line++; + } + else + *param++ = *line++; + } + *param = '\0'; /* always null-terminate */ + return line; +} + +/* + * Reads a line from the given file, ensuring is NUL terminated. + */ +static bool my_get_line(FILE *fp, struct curlx_dynbuf *db, + bool *error) +{ + char buf[4096]; + *error = FALSE; + do { + /* fgets() returns s on success, and NULL on error or when end of file + occurs while no characters have been read. */ + if(!fgets(buf, sizeof(buf), fp)) + /* only if there's data in the line, return TRUE */ + return curlx_dyn_len(db) ? TRUE : FALSE; + if(curlx_dyn_add(db, buf)) { + *error = TRUE; /* error */ + return FALSE; /* stop reading */ + } + } while(!strchr(buf, '\n')); + + return TRUE; /* continue */ +} diff --git a/contrib/libs/curl/src/tool_parsecfg.h b/contrib/libs/curl/src/tool_parsecfg.h new file mode 100644 index 0000000000..90af619615 --- /dev/null +++ b/contrib/libs/curl/src/tool_parsecfg.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_TOOL_PARSECFG_H +#define HEADER_CURL_TOOL_PARSECFG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +int parseconfig(const char *filename, struct GlobalConfig *config); + +#endif /* HEADER_CURL_TOOL_PARSECFG_H */ diff --git a/contrib/libs/curl/src/tool_progress.c b/contrib/libs/curl/src/tool_progress.c new file mode 100644 index 0000000000..46185c0d3c --- /dev/null +++ b/contrib/libs/curl/src/tool_progress.c @@ -0,0 +1,336 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#include "tool_operate.h" +#include "tool_progress.h" +#include "tool_util.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +/* The point of this function would be to return a string of the input data, + but never longer than 5 columns (+ one zero byte). + Add suffix k, M, G when suitable... */ +static char *max5data(curl_off_t bytes, char *max5) +{ +#define ONE_KILOBYTE CURL_OFF_T_C(1024) +#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE) +#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE) +#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE) +#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) + + if(bytes < CURL_OFF_T_C(100000)) + msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes); + + else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE); + + else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) + /* 'XX.XM' is good as long as we're less than 100 megs */ + msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, + (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); + +#if (SIZEOF_CURL_OFF_T > 4) + + else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) + /* 'XXXXM' is good until we're at 10000MB or above */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); + + else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) + /* 10000 MB - 100 GB, we show it as XX.XG */ + msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0" + CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE, + (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); + + else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) + /* up to 10000GB, display without decimal: XXXXG */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE); + + else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) + /* up to 10000TB, display without decimal: XXXXT */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE); + + else + /* up to 10000PB, display without decimal: XXXXP */ + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); + + /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number + can hold, but our data type is signed so 8192PB will be the maximum. */ + +#else + + else + msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); + +#endif + + return max5; +} + +int xferinfo_cb(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow) +{ + struct per_transfer *per = clientp; + struct OperationConfig *config = per->config; + per->dltotal = dltotal; + per->dlnow = dlnow; + per->ultotal = ultotal; + per->ulnow = ulnow; + + if(per->abort) + return 1; + + if(config->readbusy) { + config->readbusy = FALSE; + curl_easy_pause(per->curl, CURLPAUSE_CONT); + } + + return 0; +} + +/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero + byte) */ +static void time2str(char *r, curl_off_t seconds) +{ + curl_off_t h; + if(seconds <= 0) { + strcpy(r, "--:--:--"); + return; + } + h = seconds / CURL_OFF_T_C(3600); + if(h <= CURL_OFF_T_C(99)) { + curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); + curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); + msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T + ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s); + } + else { + /* this equals to more than 99 hours, switch to a more suitable output + format to fit within the limits. */ + curl_off_t d = seconds / CURL_OFF_T_C(86400); + h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); + if(d <= CURL_OFF_T_C(999)) + msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T + "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h); + else + msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d); + } +} + +static curl_off_t all_dltotal = 0; +static curl_off_t all_ultotal = 0; +static curl_off_t all_dlalready = 0; +static curl_off_t all_ulalready = 0; + +curl_off_t all_xfers = 0; /* current total */ + +struct speedcount { + curl_off_t dl; + curl_off_t ul; + struct timeval stamp; +}; +#define SPEEDCNT 10 +static unsigned int speedindex; +static bool indexwrapped; +static struct speedcount speedstore[SPEEDCNT]; + +/* + |DL% UL% Dled Uled Xfers Live Qd Total Current Left Speed + | 6 -- 9.9G 0 2 2 0 0:00:40 0:00:02 0:00:37 4087M +*/ +bool progress_meter(struct GlobalConfig *global, + struct timeval *start, + bool final) +{ + static struct timeval stamp; + static bool header = FALSE; + struct timeval now; + long diff; + + if(global->noprogress) + return FALSE; + + now = tvnow(); + diff = tvdiff(now, stamp); + + if(!header) { + header = TRUE; + fputs("DL% UL% Dled Uled Xfers Live Qd " + "Total Current Left Speed\n", + global->errors); + } + if(final || (diff > 500)) { + char time_left[10]; + char time_total[10]; + char time_spent[10]; + char buffer[3][6]; + curl_off_t spent = tvdiff(now, *start)/1000; + char dlpercen[4]="--"; + char ulpercen[4]="--"; + struct per_transfer *per; + curl_off_t all_dlnow = 0; + curl_off_t all_ulnow = 0; + bool dlknown = TRUE; + bool ulknown = TRUE; + curl_off_t all_running = 0; /* in progress */ + curl_off_t all_queued = 0; /* pending */ + curl_off_t speed = 0; + unsigned int i; + stamp = now; + + /* first add the amounts of the already completed transfers */ + all_dlnow += all_dlalready; + all_ulnow += all_ulalready; + + for(per = transfers; per; per = per->next) { + all_dlnow += per->dlnow; + all_ulnow += per->ulnow; + if(!per->dltotal) + dlknown = FALSE; + else if(!per->dltotal_added) { + /* only add this amount once */ + all_dltotal += per->dltotal; + per->dltotal_added = TRUE; + } + if(!per->ultotal) + ulknown = FALSE; + else if(!per->ultotal_added) { + /* only add this amount once */ + all_ultotal += per->ultotal; + per->ultotal_added = TRUE; + } + if(!per->added) + all_queued++; + else + all_running++; + } + if(dlknown && all_dltotal) + /* TODO: handle integer overflow */ + msnprintf(dlpercen, sizeof(dlpercen), "%3" CURL_FORMAT_CURL_OFF_T, + all_dlnow * 100 / all_dltotal); + if(ulknown && all_ultotal) + /* TODO: handle integer overflow */ + msnprintf(ulpercen, sizeof(ulpercen), "%3" CURL_FORMAT_CURL_OFF_T, + all_ulnow * 100 / all_ultotal); + + /* get the transfer speed, the higher of the two */ + + i = speedindex; + speedstore[i].dl = all_dlnow; + speedstore[i].ul = all_ulnow; + speedstore[i].stamp = now; + if(++speedindex >= SPEEDCNT) { + indexwrapped = TRUE; + speedindex = 0; + } + + { + long deltams; + curl_off_t dl; + curl_off_t ul; + curl_off_t dls; + curl_off_t uls; + if(indexwrapped) { + /* 'speedindex' is the oldest stored data */ + deltams = tvdiff(now, speedstore[speedindex].stamp); + dl = all_dlnow - speedstore[speedindex].dl; + ul = all_ulnow - speedstore[speedindex].ul; + } + else { + /* since the beginning */ + deltams = tvdiff(now, *start); + dl = all_dlnow; + ul = all_ulnow; + } + if(!deltams) /* no division by zero please */ + deltams++; + dls = (curl_off_t)((double)dl / ((double)deltams/1000.0)); + uls = (curl_off_t)((double)ul / ((double)deltams/1000.0)); + speed = dls > uls ? dls : uls; + } + + + if(dlknown && speed) { + curl_off_t est = all_dltotal / speed; + curl_off_t left = (all_dltotal - all_dlnow) / speed; + time2str(time_left, left); + time2str(time_total, est); + } + else { + time2str(time_left, 0); + time2str(time_total, 0); + } + time2str(time_spent, spent); + + fprintf(global->errors, + "\r" + "%-3s " /* percent downloaded */ + "%-3s " /* percent uploaded */ + "%s " /* Dled */ + "%s " /* Uled */ + "%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */ + "%5" CURL_FORMAT_CURL_OFF_T " " /* Live */ + "%5" CURL_FORMAT_CURL_OFF_T " " /* Queued */ + "%s " /* Total time */ + "%s " /* Current time */ + "%s " /* Time left */ + "%s " /* Speed */ + "%5s" /* final newline */, + + dlpercen, /* 3 letters */ + ulpercen, /* 3 letters */ + max5data(all_dlnow, buffer[0]), + max5data(all_ulnow, buffer[1]), + all_xfers, + all_running, + all_queued, + time_total, + time_spent, + time_left, + max5data(speed, buffer[2]), /* speed */ + final ? "\n" :""); + return TRUE; + } + return FALSE; +} + +void progress_finalize(struct per_transfer *per) +{ + /* get the numbers before this transfer goes away */ + all_dlalready += per->dlnow; + all_ulalready += per->ulnow; + if(!per->dltotal_added) { + all_dltotal += per->dltotal; + per->dltotal_added = TRUE; + } + if(!per->ultotal_added) { + all_ultotal += per->ultotal; + per->ultotal_added = TRUE; + } +} diff --git a/contrib/libs/curl/src/tool_progress.h b/contrib/libs/curl/src/tool_progress.h new file mode 100644 index 0000000000..5f68474ff3 --- /dev/null +++ b/contrib/libs/curl/src/tool_progress.h @@ -0,0 +1,41 @@ +#ifndef HEADER_CURL_TOOL_PROGRESS_H +#define HEADER_CURL_TOOL_PROGRESS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +int xferinfo_cb(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +bool progress_meter(struct GlobalConfig *global, + struct timeval *start, + bool final); +void progress_finalize(struct per_transfer *per); + +extern curl_off_t all_xfers; /* total number */ + +#endif /* HEADER_CURL_TOOL_PROGRESS_H */ diff --git a/contrib/libs/curl/src/tool_sdecls.h b/contrib/libs/curl/src/tool_sdecls.h new file mode 100644 index 0000000000..70e44d4ed2 --- /dev/null +++ b/contrib/libs/curl/src/tool_sdecls.h @@ -0,0 +1,144 @@ +#ifndef HEADER_CURL_TOOL_SDECLS_H +#define HEADER_CURL_TOOL_SDECLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* + * OutStruct variables keep track of information relative to curl's + * output writing, which may take place to a standard stream or a file. + * + * 'filename' member is either a pointer to a file name string or NULL + * when dealing with a standard stream. + * + * 'alloc_filename' member is TRUE when string pointed by 'filename' has been + * dynamically allocated and 'belongs' to this OutStruct, otherwise FALSE. + * + * 'is_cd_filename' member is TRUE when string pointed by 'filename' has been + * set using a server-specified Content-Disposition filename, otherwise FALSE. + * + * 's_isreg' member is TRUE when output goes to a regular file, this also + * implies that output is 'seekable' and 'appendable' and also that member + * 'filename' points to file name's string. For any standard stream member + * 's_isreg' will be FALSE. + * + * 'fopened' member is TRUE when output goes to a regular file and it + * has been fopen'ed, requiring it to be closed later on. In any other + * case this is FALSE. + * + * 'stream' member is a pointer to a stream controlling object as returned + * from a 'fopen' call or a standard stream. + * + * 'config' member is a pointer to associated 'OperationConfig' struct. + * + * 'bytes' member represents amount written so far. + * + * 'init' member holds original file size or offset at which truncation is + * taking place. Always zero unless appending to a non-empty regular file. + * + */ + +struct OutStruct { + char *filename; + bool alloc_filename; + bool is_cd_filename; + bool s_isreg; + bool fopened; + FILE *stream; + curl_off_t bytes; + curl_off_t init; +}; + + +/* + * InStruct variables keep track of information relative to curl's + * input reading, which may take place from stdin or from some file. + * + * 'fd' member is either 'stdin' file descriptor number STDIN_FILENO + * or a file descriptor as returned from an 'open' call for some file. + * + * 'config' member is a pointer to associated 'OperationConfig' struct. + */ + +struct InStruct { + int fd; + struct OperationConfig *config; +}; + + +/* + * A linked list of these 'getout' nodes contain URL's to fetch, + * as well as information relative to where URL contents should + * be stored or which file should be uploaded. + */ + +struct getout { + struct getout *next; /* next one */ + char *url; /* the URL we deal with */ + char *outfile; /* where to store the output */ + char *infile; /* file to upload, if GETOUT_UPLOAD is set */ + int flags; /* options - composed of GETOUT_* bits */ + int num; /* which URL number in an invocation */ +}; + +#define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */ +#define GETOUT_URL (1<<1) /* set when URL is deemed done */ +#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */ +#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */ +#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */ + +/* + * 'trace' enumeration represents curl's output look'n feel possibilities. + */ + +typedef enum { + TRACE_NONE, /* no trace/verbose output at all */ + TRACE_BIN, /* tcpdump inspired look */ + TRACE_ASCII, /* like *BIN but without the hex output */ + TRACE_PLAIN /* -v/--verbose type */ +} trace; + + +/* + * 'HttpReq' enumeration represents HTTP request types. + */ + +typedef enum { + HTTPREQ_UNSPEC, /* first in list */ + HTTPREQ_GET, + HTTPREQ_HEAD, + HTTPREQ_MIMEPOST, + HTTPREQ_SIMPLEPOST, + HTTPREQ_PUT +} HttpReq; + + +/* + * Complete struct declarations which have OperationConfig struct members, + * just in case this header is directly included in some source file. + */ + +#include "tool_cfgable.h" + +#endif /* HEADER_CURL_TOOL_SDECLS_H */ diff --git a/contrib/libs/curl/src/tool_setopt.c b/contrib/libs/curl/src/tool_setopt.c new file mode 100644 index 0000000000..5ff86c7f5b --- /dev/null +++ b/contrib/libs/curl/src/tool_setopt.c @@ -0,0 +1,749 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifndef CURL_DISABLE_LIBCURL_OPTION + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_easysrc.h" +#include "tool_setopt.h" +#include "tool_msgs.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* Lookup tables for converting setopt values back to symbols */ +/* For enums, values may be in any order. */ +/* For bit masks, put combinations first, then single bits, */ +/* and finally any "NONE" value. */ + +#define NV(e) {#e, e} +#define NV1(e, v) {#e, (v)} +#define NVEND {NULL, 0} /* sentinel to mark end of list */ + +const struct NameValue setopt_nv_CURLPROXY[] = { + NV(CURLPROXY_HTTP), + NV(CURLPROXY_HTTP_1_0), + NV(CURLPROXY_HTTPS), + NV(CURLPROXY_SOCKS4), + NV(CURLPROXY_SOCKS5), + NV(CURLPROXY_SOCKS4A), + NV(CURLPROXY_SOCKS5_HOSTNAME), + NVEND, +}; + +const struct NameValue setopt_nv_CURL_SOCKS_PROXY[] = { + NV(CURLPROXY_SOCKS4), + NV(CURLPROXY_SOCKS5), + NV(CURLPROXY_SOCKS4A), + NV(CURLPROXY_SOCKS5_HOSTNAME), + NVEND, +}; + +const struct NameValueUnsigned setopt_nv_CURLHSTS[] = { + NV(CURLHSTS_ENABLE), + NVEND, +}; + +const struct NameValueUnsigned setopt_nv_CURLAUTH[] = { + NV(CURLAUTH_ANY), /* combination */ + NV(CURLAUTH_ANYSAFE), /* combination */ + NV(CURLAUTH_BASIC), + NV(CURLAUTH_DIGEST), + NV(CURLAUTH_GSSNEGOTIATE), + NV(CURLAUTH_NTLM), + NV(CURLAUTH_DIGEST_IE), + NV(CURLAUTH_NTLM_WB), + NV(CURLAUTH_ONLY), + NV(CURLAUTH_NONE), + NVEND, +}; + +const struct NameValue setopt_nv_CURL_HTTP_VERSION[] = { + NV(CURL_HTTP_VERSION_NONE), + NV(CURL_HTTP_VERSION_1_0), + NV(CURL_HTTP_VERSION_1_1), + NV(CURL_HTTP_VERSION_2_0), + NV(CURL_HTTP_VERSION_2TLS), + NV(CURL_HTTP_VERSION_3), + NVEND, +}; + +const struct NameValue setopt_nv_CURL_SSLVERSION[] = { + NV(CURL_SSLVERSION_DEFAULT), + NV(CURL_SSLVERSION_TLSv1), + NV(CURL_SSLVERSION_SSLv2), + NV(CURL_SSLVERSION_SSLv3), + NV(CURL_SSLVERSION_TLSv1_0), + NV(CURL_SSLVERSION_TLSv1_1), + NV(CURL_SSLVERSION_TLSv1_2), + NV(CURL_SSLVERSION_TLSv1_3), + NVEND, +}; + +const struct NameValue setopt_nv_CURL_TIMECOND[] = { + NV(CURL_TIMECOND_IFMODSINCE), + NV(CURL_TIMECOND_IFUNMODSINCE), + NV(CURL_TIMECOND_LASTMOD), + NV(CURL_TIMECOND_NONE), + NVEND, +}; + +const struct NameValue setopt_nv_CURLFTPSSL_CCC[] = { + NV(CURLFTPSSL_CCC_NONE), + NV(CURLFTPSSL_CCC_PASSIVE), + NV(CURLFTPSSL_CCC_ACTIVE), + NVEND, +}; + +const struct NameValue setopt_nv_CURLUSESSL[] = { + NV(CURLUSESSL_NONE), + NV(CURLUSESSL_TRY), + NV(CURLUSESSL_CONTROL), + NV(CURLUSESSL_ALL), + NVEND, +}; + +const struct NameValueUnsigned setopt_nv_CURLSSLOPT[] = { + NV(CURLSSLOPT_ALLOW_BEAST), + NV(CURLSSLOPT_NO_REVOKE), + NV(CURLSSLOPT_NO_PARTIALCHAIN), + NV(CURLSSLOPT_REVOKE_BEST_EFFORT), + NV(CURLSSLOPT_NATIVE_CA), + NV(CURLSSLOPT_AUTO_CLIENT_CERT), + NVEND, +}; + +const struct NameValue setopt_nv_CURL_NETRC[] = { + NV(CURL_NETRC_IGNORED), + NV(CURL_NETRC_OPTIONAL), + NV(CURL_NETRC_REQUIRED), + NVEND, +}; + +/* These mappings essentially triplicated - see + * tool_libinfo.c and tool_paramhlp.c */ +const struct NameValue setopt_nv_CURLPROTO[] = { + NV(CURLPROTO_ALL), /* combination */ + NV(CURLPROTO_DICT), + NV(CURLPROTO_FILE), + NV(CURLPROTO_FTP), + NV(CURLPROTO_FTPS), + NV(CURLPROTO_GOPHER), + NV(CURLPROTO_HTTP), + NV(CURLPROTO_HTTPS), + NV(CURLPROTO_IMAP), + NV(CURLPROTO_IMAPS), + NV(CURLPROTO_LDAP), + NV(CURLPROTO_LDAPS), + NV(CURLPROTO_POP3), + NV(CURLPROTO_POP3S), + NV(CURLPROTO_RTSP), + NV(CURLPROTO_SCP), + NV(CURLPROTO_SFTP), + NV(CURLPROTO_SMB), + NV(CURLPROTO_SMBS), + NV(CURLPROTO_SMTP), + NV(CURLPROTO_SMTPS), + NV(CURLPROTO_TELNET), + NV(CURLPROTO_TFTP), + NVEND, +}; + +/* These options have non-zero default values. */ +static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { + NV1(CURLOPT_SSL_VERIFYPEER, 1), + NV1(CURLOPT_SSL_VERIFYHOST, 1), + NV1(CURLOPT_SSL_ENABLE_NPN, 1), + NV1(CURLOPT_SSL_ENABLE_ALPN, 1), + NV1(CURLOPT_TCP_NODELAY, 1), + NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1), + NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1), + NV1(CURLOPT_SOCKS5_AUTH, 1), + NVEND +}; + +/* Format and add code; jump to nomem on malloc error */ +#define ADD(args) do { \ + ret = easysrc_add args; \ + if(ret) \ + goto nomem; \ +} while(0) +#define ADDF(args) do { \ + ret = easysrc_addf args; \ + if(ret) \ + goto nomem; \ +} while(0) +#define NULL_CHECK(p) do { \ + if(!p) { \ + ret = CURLE_OUT_OF_MEMORY; \ + goto nomem; \ + } \ +} while(0) + +#define DECL0(s) ADD((&easysrc_decl, s)) +#define DECL1(f,a) ADDF((&easysrc_decl, f,a)) + +#define DATA0(s) ADD((&easysrc_data, s)) +#define DATA1(f,a) ADDF((&easysrc_data, f,a)) +#define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b)) +#define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c)) + +#define CODE0(s) ADD((&easysrc_code, s)) +#define CODE1(f,a) ADDF((&easysrc_code, f,a)) +#define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b)) +#define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c)) + +#define CLEAN0(s) ADD((&easysrc_clean, s)) +#define CLEAN1(f,a) ADDF((&easysrc_clean, f,a)) + +#define REM0(s) ADD((&easysrc_toohard, s)) +#define REM1(f,a) ADDF((&easysrc_toohard, f,a)) +#define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b)) + +/* Escape string to C string syntax. Return NULL if out of memory. + * Is this correct for those wacky EBCDIC guys? */ + +#define MAX_STRING_LENGTH_OUTPUT 2000 +#define ZERO_TERMINATED -1 + +static char *c_escape(const char *str, curl_off_t len) +{ + const char *s; + unsigned char c; + char *escaped, *e; + unsigned int cutoff = 0; + + if(len == ZERO_TERMINATED) + len = strlen(str); + + if(len > MAX_STRING_LENGTH_OUTPUT) { + /* cap ridiculously long strings */ + len = MAX_STRING_LENGTH_OUTPUT; + cutoff = 3; + } + + /* Allocate space based on worst-case */ + escaped = malloc(4 * (size_t)len + 1 + cutoff); + if(!escaped) + return NULL; + + e = escaped; + for(s = str; len; s++, len--) { + c = *s; + if(c == '\n') { + strcpy(e, "\\n"); + e += 2; + } + else if(c == '\r') { + strcpy(e, "\\r"); + e += 2; + } + else if(c == '\t') { + strcpy(e, "\\t"); + e += 2; + } + else if(c == '\\') { + strcpy(e, "\\\\"); + e += 2; + } + else if(c == '"') { + strcpy(e, "\\\""); + e += 2; + } + else if(c == '?') { + /* escape question marks as well, to prevent generating accidental + trigraphs */ + strcpy(e, "\\?"); + e += 2; + } + else if(!isprint(c)) { + msnprintf(e, 5, "\\x%02x", (unsigned)c); + e += 4; + } + else + *e++ = c; + } + while(cutoff--) + *e++ = '.'; + *e = '\0'; + return escaped; +} + +/* setopt wrapper for enum types */ +CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + const struct NameValue *nvlist, long lval) +{ + CURLcode ret = CURLE_OK; + bool skip = FALSE; + + ret = curl_easy_setopt(curl, tag, lval); + if(!lval) + skip = TRUE; + + if(config->libcurl && !skip && !ret) { + /* we only use this for real if --libcurl was used */ + const struct NameValue *nv = NULL; + for(nv = nvlist; nv->name; nv++) { + if(nv->value == lval) + break; /* found it */ + } + if(!nv->name) { + /* If no definition was found, output an explicit value. + * This could happen if new values are defined and used + * but the NameValue list is not updated. */ + CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval); + } + else { + CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name); + } + } + +#ifdef DEBUGBUILD + if(ret) + warnf(config, "option %s returned error (%d)\n", name, (int)ret); +#endif + nomem: + return ret; +} + +/* setopt wrapper for flags */ +CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + const struct NameValue *nvlist, long lval) +{ + CURLcode ret = CURLE_OK; + bool skip = FALSE; + + ret = curl_easy_setopt(curl, tag, lval); + if(!lval) + skip = TRUE; + + if(config->libcurl && !skip && !ret) { + /* we only use this for real if --libcurl was used */ + char preamble[80]; /* should accommodate any symbol name */ + long rest = lval; /* bits not handled yet */ + const struct NameValue *nv = NULL; + msnprintf(preamble, sizeof(preamble), + "curl_easy_setopt(hnd, %s, ", name); + for(nv = nvlist; nv->name; nv++) { + if((nv->value & ~ rest) == 0) { + /* all value flags contained in rest */ + rest &= ~ nv->value; /* remove bits handled here */ + CODE3("%s(long)%s%s", + preamble, nv->name, rest ? " |" : ");"); + if(!rest) + break; /* handled them all */ + /* replace with all spaces for continuation line */ + msnprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); + } + } + /* If any bits have no definition, output an explicit value. + * This could happen if new bits are defined and used + * but the NameValue list is not updated. */ + if(rest) + CODE2("%s%ldL);", preamble, rest); + } + + nomem: + return ret; +} + +/* setopt wrapper for bitmasks */ +CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + const struct NameValueUnsigned *nvlist, + long lval) +{ + CURLcode ret = CURLE_OK; + bool skip = FALSE; + + ret = curl_easy_setopt(curl, tag, lval); + if(!lval) + skip = TRUE; + + if(config->libcurl && !skip && !ret) { + /* we only use this for real if --libcurl was used */ + char preamble[80]; + unsigned long rest = (unsigned long)lval; + const struct NameValueUnsigned *nv = NULL; + msnprintf(preamble, sizeof(preamble), + "curl_easy_setopt(hnd, %s, ", name); + for(nv = nvlist; nv->name; nv++) { + if((nv->value & ~ rest) == 0) { + /* all value flags contained in rest */ + rest &= ~ nv->value; /* remove bits handled here */ + CODE3("%s(long)%s%s", + preamble, nv->name, rest ? " |" : ");"); + if(!rest) + break; /* handled them all */ + /* replace with all spaces for continuation line */ + msnprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); + } + } + /* If any bits have no definition, output an explicit value. + * This could happen if new bits are defined and used + * but the NameValue list is not updated. */ + if(rest) + CODE2("%s%luUL);", preamble, rest); + } + + nomem: + return ret; +} + +/* Generate code for a struct curl_slist. */ +static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno) +{ + CURLcode ret = CURLE_OK; + char *escaped = NULL; + + /* May need several slist variables, so invent name */ + *slistno = ++easysrc_slist_count; + + DECL1("struct curl_slist *slist%d;", *slistno); + DATA1("slist%d = NULL;", *slistno); + CLEAN1("curl_slist_free_all(slist%d);", *slistno); + CLEAN1("slist%d = NULL;", *slistno); + for(; slist; slist = slist->next) { + Curl_safefree(escaped); + escaped = c_escape(slist->data, ZERO_TERMINATED); + if(!escaped) + return CURLE_OUT_OF_MEMORY; + DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", + *slistno, *slistno, escaped); + } + + nomem: + Curl_safefree(escaped); + return ret; +} + +static CURLcode libcurl_generate_mime(CURL *curl, + struct GlobalConfig *config, + struct tool_mime *toolmime, + int *mimeno); /* Forward. */ + +/* Wrapper to generate source code for a mime part. */ +static CURLcode libcurl_generate_mime_part(CURL *curl, + struct GlobalConfig *config, + struct tool_mime *part, + int mimeno) +{ + CURLcode ret = CURLE_OK; + int submimeno = 0; + char *escaped = NULL; + const char *data = NULL; + const char *filename = part->filename; + + /* Parts are linked in reverse order. */ + if(part->prev) { + ret = libcurl_generate_mime_part(curl, config, part->prev, mimeno); + if(ret) + return ret; + } + + /* Create the part. */ + CODE2("part%d = curl_mime_addpart(mime%d);", mimeno, mimeno); + + switch(part->kind) { + case TOOLMIME_PARTS: + ret = libcurl_generate_mime(curl, config, part, &submimeno); + if(!ret) { + CODE2("curl_mime_subparts(part%d, mime%d);", mimeno, submimeno); + CODE1("mime%d = NULL;", submimeno); /* Avoid freeing in CLEAN. */ + } + break; + + case TOOLMIME_DATA: + data = part->data; + if(!ret) { + Curl_safefree(escaped); + escaped = c_escape(data, ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_data(part%d, \"%s\", CURL_ZERO_TERMINATED);", + mimeno, escaped); + } + break; + + case TOOLMIME_FILE: + case TOOLMIME_FILEDATA: + escaped = c_escape(part->data, ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_filedata(part%d, \"%s\");", mimeno, escaped); + if(part->kind == TOOLMIME_FILEDATA && !filename) { + CODE1("curl_mime_filename(part%d, NULL);", mimeno); + } + break; + + case TOOLMIME_STDIN: + if(!filename) + filename = "-"; + /* FALLTHROUGH */ + case TOOLMIME_STDINDATA: + /* Can only be reading stdin in the current context. */ + CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\", + mimeno); + CODE0(" (curl_seek_callback) fseek, NULL, stdin);"); + break; + default: + /* Other cases not possible in this context. */ + break; + } + + if(!ret && part->encoder) { + Curl_safefree(escaped); + escaped = c_escape(part->encoder, ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_encoder(part%d, \"%s\");", mimeno, escaped); + } + + if(!ret && filename) { + Curl_safefree(escaped); + escaped = c_escape(filename, ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_filename(part%d, \"%s\");", mimeno, escaped); + } + + if(!ret && part->name) { + Curl_safefree(escaped); + escaped = c_escape(part->name, ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_name(part%d, \"%s\");", mimeno, escaped); + } + + if(!ret && part->type) { + Curl_safefree(escaped); + escaped = c_escape(part->type, ZERO_TERMINATED); + NULL_CHECK(escaped); + CODE2("curl_mime_type(part%d, \"%s\");", mimeno, escaped); + } + + if(!ret && part->headers) { + int slistno; + + ret = libcurl_generate_slist(part->headers, &slistno); + if(!ret) { + CODE2("curl_mime_headers(part%d, slist%d, 1);", mimeno, slistno); + CODE1("slist%d = NULL;", slistno); /* Prevent CLEANing. */ + } + } + +nomem: + Curl_safefree(escaped); + return ret; +} + +/* Wrapper to generate source code for a mime structure. */ +static CURLcode libcurl_generate_mime(CURL *curl, + struct GlobalConfig *config, + struct tool_mime *toolmime, + int *mimeno) +{ + CURLcode ret = CURLE_OK; + + /* May need several mime variables, so invent name. */ + *mimeno = ++easysrc_mime_count; + DECL1("curl_mime *mime%d;", *mimeno); + DATA1("mime%d = NULL;", *mimeno); + CODE1("mime%d = curl_mime_init(hnd);", *mimeno); + CLEAN1("curl_mime_free(mime%d);", *mimeno); + CLEAN1("mime%d = NULL;", *mimeno); + + if(toolmime->subparts) { + DECL1("curl_mimepart *part%d;", *mimeno); + ret = libcurl_generate_mime_part(curl, config, + toolmime->subparts, *mimeno); + } + +nomem: + return ret; +} + +/* setopt wrapper for CURLOPT_MIMEPOST */ +CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + curl_mime *mimepost) +{ + CURLcode ret = curl_easy_setopt(curl, tag, mimepost); + int mimeno = 0; + + if(!ret && config->libcurl) { + ret = libcurl_generate_mime(curl, config, + config->current->mimeroot, &mimeno); + + if(!ret) + CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, mimeno); + } + +nomem: + return ret; +} + +/* setopt wrapper for curl_slist options */ +CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + struct curl_slist *list) +{ + CURLcode ret = CURLE_OK; + + ret = curl_easy_setopt(curl, tag, list); + + if(config->libcurl && list && !ret) { + int i; + + ret = libcurl_generate_slist(list, &i); + if(!ret) + CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i); + } + + nomem: + return ret; +} + +/* generic setopt wrapper for all other options. + * Some type information is encoded in the tag value. */ +CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global, + struct OperationConfig *config, + const char *name, CURLoption tag, ...) +{ + va_list arg; + char buf[256]; + const char *value = NULL; + bool remark = FALSE; + bool skip = FALSE; + bool escape = FALSE; + char *escaped = NULL; + CURLcode ret = CURLE_OK; + + va_start(arg, tag); + + if(tag < CURLOPTTYPE_OBJECTPOINT) { + /* Value is expected to be a long */ + long lval = va_arg(arg, long); + long defval = 0L; + const struct NameValue *nv = NULL; + for(nv = setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) { + if(!strcmp(name, nv->name)) { + defval = nv->value; + break; /* found it */ + } + } + + msnprintf(buf, sizeof(buf), "%ldL", lval); + value = buf; + ret = curl_easy_setopt(curl, tag, lval); + if(lval == defval) + skip = TRUE; + } + else if(tag < CURLOPTTYPE_OFF_T) { + /* Value is some sort of object pointer */ + void *pval = va_arg(arg, void *); + + /* function pointers are never printable */ + if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { + if(pval) { + value = "functionpointer"; + remark = TRUE; + } + else + skip = TRUE; + } + + else if(pval && str) { + value = (char *)pval; + escape = TRUE; + } + else if(pval) { + value = "objectpointer"; + remark = TRUE; + } + else + skip = TRUE; + + ret = curl_easy_setopt(curl, tag, pval); + + } + else if(tag < CURLOPTTYPE_BLOB) { + /* Value is expected to be curl_off_t */ + curl_off_t oval = va_arg(arg, curl_off_t); + msnprintf(buf, sizeof(buf), + "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval); + value = buf; + ret = curl_easy_setopt(curl, tag, oval); + + if(!oval) + skip = TRUE; + } + else { + /* Value is a blob */ + void *pblob = va_arg(arg, void *); + + /* blobs are never printable */ + if(pblob) { + value = "blobpointer"; + remark = TRUE; + } + else + skip = TRUE; + + ret = curl_easy_setopt(curl, tag, pblob); + } + + va_end(arg); + + if(global->libcurl && !skip && !ret) { + /* we only use this for real if --libcurl was used */ + + if(remark) + REM2("%s set to a %s", name, value); + else { + if(escape) { + curl_off_t len = ZERO_TERMINATED; + if(tag == CURLOPT_POSTFIELDS) + len = config->postfieldsize; + escaped = c_escape(value, len); + NULL_CHECK(escaped); + CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped); + } + else + CODE2("curl_easy_setopt(hnd, %s, %s);", name, value); + } + } + + nomem: + Curl_safefree(escaped); + return ret; +} + +#else /* CURL_DISABLE_LIBCURL_OPTION */ + +#include "tool_cfgable.h" +#include "tool_setopt.h" + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ diff --git a/contrib/libs/curl/src/tool_setopt.h b/contrib/libs/curl/src/tool_setopt.h new file mode 100644 index 0000000000..2646edb44b --- /dev/null +++ b/contrib/libs/curl/src/tool_setopt.h @@ -0,0 +1,159 @@ +#ifndef HEADER_CURL_TOOL_SETOPT_H +#define HEADER_CURL_TOOL_SETOPT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "tool_formparse.h" + +/* + * Macros used in operate() + */ + +#define SETOPT_CHECK(v,opt) do { \ + result = (v); \ + } while(0) + +#ifndef CURL_DISABLE_LIBCURL_OPTION + +/* Associate symbolic names with option values */ +struct NameValue { + const char *name; + long value; +}; + +struct NameValueUnsigned { + const char *name; + unsigned long value; +}; + +extern const struct NameValue setopt_nv_CURLPROXY[]; +extern const struct NameValue setopt_nv_CURL_SOCKS_PROXY[]; +extern const struct NameValue setopt_nv_CURL_HTTP_VERSION[]; +extern const struct NameValue setopt_nv_CURL_SSLVERSION[]; +extern const struct NameValue setopt_nv_CURL_TIMECOND[]; +extern const struct NameValue setopt_nv_CURLFTPSSL_CCC[]; +extern const struct NameValue setopt_nv_CURLUSESSL[]; +extern const struct NameValueUnsigned setopt_nv_CURLSSLOPT[]; +extern const struct NameValue setopt_nv_CURL_NETRC[]; +extern const struct NameValue setopt_nv_CURLPROTO[]; +extern const struct NameValueUnsigned setopt_nv_CURLAUTH[]; +extern const struct NameValueUnsigned setopt_nv_CURLHSTS[]; + +/* Map options to NameValue sets */ +#define setopt_nv_CURLOPT_HSTS_CTRL setopt_nv_CURLHSTS +#define setopt_nv_CURLOPT_HTTP_VERSION setopt_nv_CURL_HTTP_VERSION +#define setopt_nv_CURLOPT_HTTPAUTH setopt_nv_CURLAUTH +#define setopt_nv_CURLOPT_SSLVERSION setopt_nv_CURL_SSLVERSION +#define setopt_nv_CURLOPT_PROXY_SSLVERSION setopt_nv_CURL_SSLVERSION +#define setopt_nv_CURLOPT_TIMECONDITION setopt_nv_CURL_TIMECOND +#define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC +#define setopt_nv_CURLOPT_USE_SSL setopt_nv_CURLUSESSL +#define setopt_nv_CURLOPT_SSL_OPTIONS setopt_nv_CURLSSLOPT +#define setopt_nv_CURLOPT_PROXY_SSL_OPTIONS setopt_nv_CURLSSLOPT +#define setopt_nv_CURLOPT_NETRC setopt_nv_CURL_NETRC +#define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO +#define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO +#define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY +#define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH +#define setopt_nv_CURLOPT_SOCKS5_AUTH setopt_nv_CURLAUTH + +/* Intercept setopt calls for --libcurl */ + +CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + const struct NameValue *nv, long lval); +CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + const struct NameValue *nv, long lval); +CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + const struct NameValueUnsigned *nv, long lval); +CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + curl_mime *mimepost); +CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config, + const char *name, CURLoption tag, + struct curl_slist *list); +CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global, + struct OperationConfig *config, + const char *name, CURLoption tag, ...); + +#define my_setopt(x,y,z) \ + SETOPT_CHECK(tool_setopt(x, FALSE, global, config, #y, y, z), y) + +#define my_setopt_str(x,y,z) \ + SETOPT_CHECK(tool_setopt(x, TRUE, global, config, #y, y, z), y) + +#define my_setopt_enum(x,y,z) \ + SETOPT_CHECK(tool_setopt_enum(x, global, #y, y, setopt_nv_ ## y, z), y) + +#define my_setopt_flags(x,y,z) \ + SETOPT_CHECK(tool_setopt_flags(x, global, #y, y, setopt_nv_ ## y, z), y) + +#define my_setopt_bitmask(x,y,z) \ + SETOPT_CHECK(tool_setopt_bitmask(x, global, #y, y, setopt_nv_ ## y, z), y) + +#define my_setopt_mimepost(x,y,z) \ + SETOPT_CHECK(tool_setopt_mimepost(x, global, #y, y, z), y) + +#define my_setopt_slist(x,y,z) \ + SETOPT_CHECK(tool_setopt_slist(x, global, #y, y, z), y) + +#define res_setopt(x,y,z) tool_setopt(x, FALSE, global, config, #y, y, z) + +#define res_setopt_str(x,y,z) tool_setopt(x, TRUE, global, config, #y, y, z) + +#else /* CURL_DISABLE_LIBCURL_OPTION */ + +/* No --libcurl, so pass options directly to library */ + +#define my_setopt(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z), y) + +#define my_setopt_str(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z), y) + +#define my_setopt_enum(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z), y) + +#define my_setopt_flags(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z), y) + +#define my_setopt_bitmask(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z), y) + +#define my_setopt_mimepost(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z), y) + +#define my_setopt_slist(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z), y) + +#define res_setopt(x,y,z) curl_easy_setopt(x,y,z) + +#define res_setopt_str(x,y,z) curl_easy_setopt(x,y,z) + +#endif /* CURL_DISABLE_LIBCURL_OPTION */ + +#endif /* HEADER_CURL_TOOL_SETOPT_H */ diff --git a/contrib/libs/curl/src/tool_setup.h b/contrib/libs/curl/src/tool_setup.h new file mode 100644 index 0000000000..16fa00e7d1 --- /dev/null +++ b/contrib/libs/curl/src/tool_setup.h @@ -0,0 +1,67 @@ +#ifndef HEADER_CURL_TOOL_SETUP_H +#define HEADER_CURL_TOOL_SETUP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#define CURL_NO_OLDIES + +/* + * curl_setup.h may define preprocessor macros such as _FILE_OFFSET_BITS and + * _LARGE_FILES in order to support files larger than 2 GB. On platforms + * where this happens it is mandatory that these macros are defined before + * any system header file is included, otherwise file handling function + * prototypes will be misdeclared and curl tool may not build properly; + * therefore we must include curl_setup.h before curl.h when building curl. + */ + +#include "curl_setup.h" /* from the lib directory */ + +/* + * curl tool certainly uses libcurl's external interface. + */ + +#include <curl/curl.h> /* external interface */ + +/* + * Platform specific stuff. + */ + +#if defined(macintosh) && defined(__MRC__) +# define main(x,y) curl_main(x,y) +#endif + +#ifndef OS +# define OS "unknown" +#endif + +#ifndef UNPRINTABLE_CHAR + /* define what to use for unprintable characters */ +# define UNPRINTABLE_CHAR '.' +#endif + +#ifndef HAVE_STRDUP +# include "tool_strdup.h" +#endif + +#endif /* HEADER_CURL_TOOL_SETUP_H */ diff --git a/contrib/libs/curl/src/tool_sleep.c b/contrib/libs/curl/src/tool_sleep.c new file mode 100644 index 0000000000..c52425f9ab --- /dev/null +++ b/contrib/libs/curl/src/tool_sleep.c @@ -0,0 +1,61 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#elif defined(HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#ifdef HAVE_POLL_H +# include <poll.h> +#elif defined(HAVE_SYS_POLL_H) +# include <sys/poll.h> +#endif + +#ifdef MSDOS +# include <dos.h> +#endif + +#include "tool_sleep.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void tool_go_sleep(long ms) +{ +#if defined(MSDOS) + delay(ms); +#elif defined(WIN32) + Sleep(ms); +#elif defined(HAVE_POLL_FINE) + (void)poll((void *)0, 0, (int)ms); +#else + struct timeval timeout; + timeout.tv_sec = ms / 1000L; + ms = ms % 1000L; + timeout.tv_usec = (int)ms * 1000; + select(0, NULL, NULL, NULL, &timeout); +#endif +} diff --git a/contrib/libs/curl/src/tool_sleep.h b/contrib/libs/curl/src/tool_sleep.h new file mode 100644 index 0000000000..d84b467a42 --- /dev/null +++ b/contrib/libs/curl/src/tool_sleep.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_TOOL_SLEEP_H +#define HEADER_CURL_TOOL_SLEEP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +void tool_go_sleep(long ms); + +#endif /* HEADER_CURL_TOOL_SLEEP_H */ diff --git a/contrib/libs/curl/src/tool_strdup.c b/contrib/libs/curl/src/tool_strdup.c new file mode 100644 index 0000000000..402f1c9827 --- /dev/null +++ b/contrib/libs/curl/src/tool_strdup.c @@ -0,0 +1,44 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_strdup.h" + +#ifndef HAVE_STRDUP +char *strdup(const char *str) +{ + size_t len; + char *newstr; + + if(!str) + return (char *)NULL; + + len = strlen(str) + 1; + + newstr = malloc(len); + if(!newstr) + return (char *)NULL; + + memcpy(newstr, str, len); + return newstr; +} +#endif diff --git a/contrib/libs/curl/src/tool_strdup.h b/contrib/libs/curl/src/tool_strdup.h new file mode 100644 index 0000000000..c31c046522 --- /dev/null +++ b/contrib/libs/curl/src/tool_strdup.h @@ -0,0 +1,32 @@ +#ifndef HEADER_TOOL_STRDUP_H +#define HEADER_TOOL_STRDUP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifndef HAVE_STRDUP +extern char *strdup(const char *str); +#endif + +#endif /* HEADER_TOOL_STRDUP_H */ diff --git a/contrib/libs/curl/src/tool_urlglob.c b/contrib/libs/curl/src/tool_urlglob.c new file mode 100644 index 0000000000..fae8b131f8 --- /dev/null +++ b/contrib/libs/curl/src/tool_urlglob.c @@ -0,0 +1,710 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" +#include "tool_cfgable.h" +#include "tool_doswin.h" +#include "tool_urlglob.h" +#include "tool_vms.h" +#include "dynbuf.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#define GLOBERROR(string, column, code) \ + glob->error = string, glob->pos = column, code + +static CURLcode glob_fixed(struct URLGlob *glob, char *fixed, size_t len) +{ + struct URLPattern *pat = &glob->pattern[glob->size]; + pat->type = UPTSet; + pat->content.Set.size = 1; + pat->content.Set.ptr_s = 0; + pat->globindex = -1; + + pat->content.Set.elements = malloc(sizeof(char *)); + + if(!pat->content.Set.elements) + return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); + + pat->content.Set.elements[0] = malloc(len + 1); + if(!pat->content.Set.elements[0]) + return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); + + memcpy(pat->content.Set.elements[0], fixed, len); + pat->content.Set.elements[0][len] = 0; + + return CURLE_OK; +} + +/* multiply + * + * Multiplies and checks for overflow. + */ +static int multiply(unsigned long *amount, long with) +{ + unsigned long sum = *amount * with; + if(!with) { + *amount = 0; + return 0; + } + if(sum/with != *amount) + return 1; /* didn't fit, bail out */ + *amount = sum; + return 0; +} + +static CURLcode glob_set(struct URLGlob *glob, char **patternp, + size_t *posp, unsigned long *amount, + int globindex) +{ + /* processes a set expression with the point behind the opening '{' + ','-separated elements are collected until the next closing '}' + */ + struct URLPattern *pat; + bool done = FALSE; + char *buf = glob->glob_buffer; + char *pattern = *patternp; + char *opattern = pattern; + size_t opos = *posp-1; + + pat = &glob->pattern[glob->size]; + /* patterns 0,1,2,... correspond to size=1,3,5,... */ + pat->type = UPTSet; + pat->content.Set.size = 0; + pat->content.Set.ptr_s = 0; + pat->content.Set.elements = NULL; + pat->globindex = globindex; + + while(!done) { + switch (*pattern) { + case '\0': /* URL ended while set was still open */ + return GLOBERROR("unmatched brace", opos, CURLE_URL_MALFORMAT); + + case '{': + case '[': /* no nested expressions at this time */ + return GLOBERROR("nested brace", *posp, CURLE_URL_MALFORMAT); + + case '}': /* set element completed */ + if(opattern == pattern) + return GLOBERROR("empty string within braces", *posp, + CURLE_URL_MALFORMAT); + + /* add 1 to size since it'll be incremented below */ + if(multiply(amount, pat->content.Set.size + 1)) + return GLOBERROR("range overflow", 0, CURLE_URL_MALFORMAT); + + /* FALLTHROUGH */ + case ',': + + *buf = '\0'; + if(pat->content.Set.elements) { + char **new_arr = realloc(pat->content.Set.elements, + (pat->content.Set.size + 1) * sizeof(char *)); + if(!new_arr) + return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); + + pat->content.Set.elements = new_arr; + } + else + pat->content.Set.elements = malloc(sizeof(char *)); + + if(!pat->content.Set.elements) + return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); + + pat->content.Set.elements[pat->content.Set.size] = + strdup(glob->glob_buffer); + if(!pat->content.Set.elements[pat->content.Set.size]) + return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY); + ++pat->content.Set.size; + + if(*pattern == '}') { + pattern++; /* pass the closing brace */ + done = TRUE; + continue; + } + + buf = glob->glob_buffer; + ++pattern; + ++(*posp); + break; + + case ']': /* illegal closing bracket */ + return GLOBERROR("unexpected close bracket", *posp, CURLE_URL_MALFORMAT); + + case '\\': /* escaped character, skip '\' */ + if(pattern[1]) { + ++pattern; + ++(*posp); + } + /* FALLTHROUGH */ + default: + *buf++ = *pattern++; /* copy character to set element */ + ++(*posp); + } + } + + *patternp = pattern; /* return with the new position */ + return CURLE_OK; +} + +static CURLcode glob_range(struct URLGlob *glob, char **patternp, + size_t *posp, unsigned long *amount, + int globindex) +{ + /* processes a range expression with the point behind the opening '[' + - char range: e.g. "a-z]", "B-Q]" + - num range: e.g. "0-9]", "17-2000]" + - num range with leading zeros: e.g. "001-999]" + expression is checked for well-formedness and collected until the next ']' + */ + struct URLPattern *pat; + int rc; + char *pattern = *patternp; + char *c; + + pat = &glob->pattern[glob->size]; + pat->globindex = globindex; + + if(ISALPHA(*pattern)) { + /* character range detected */ + char min_c; + char max_c; + char end_c; + unsigned long step = 1; + + pat->type = UPTCharRange; + + rc = sscanf(pattern, "%c-%c%c", &min_c, &max_c, &end_c); + + if(rc == 3) { + if(end_c == ':') { + char *endp; + errno = 0; + step = strtoul(&pattern[4], &endp, 10); + if(errno || &pattern[4] == endp || *endp != ']') + step = 0; + else + pattern = endp + 1; + } + else if(end_c != ']') + /* then this is wrong */ + rc = 0; + else + /* end_c == ']' */ + pattern += 4; + } + + *posp += (pattern - *patternp); + + if(rc != 3 || !step || step > (unsigned)INT_MAX || + (min_c == max_c && step != 1) || + (min_c != max_c && (min_c > max_c || step > (unsigned)(max_c - min_c) || + (max_c - min_c) > ('z' - 'a')))) + /* the pattern is not well-formed */ + return GLOBERROR("bad range", *posp, CURLE_URL_MALFORMAT); + + /* if there was a ":[num]" thing, use that as step or else use 1 */ + pat->content.CharRange.step = (int)step; + pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c; + pat->content.CharRange.max_c = max_c; + + if(multiply(amount, ((pat->content.CharRange.max_c - + pat->content.CharRange.min_c) / + pat->content.CharRange.step + 1))) + return GLOBERROR("range overflow", *posp, CURLE_URL_MALFORMAT); + } + else if(ISDIGIT(*pattern)) { + /* numeric range detected */ + unsigned long min_n; + unsigned long max_n = 0; + unsigned long step_n = 0; + char *endp; + + pat->type = UPTNumRange; + pat->content.NumRange.padlength = 0; + + if(*pattern == '0') { + /* leading zero specified, count them! */ + c = pattern; + while(ISDIGIT(*c)) { + c++; + ++pat->content.NumRange.padlength; /* padding length is set for all + instances of this pattern */ + } + } + + errno = 0; + min_n = strtoul(pattern, &endp, 10); + if(errno || (endp == pattern)) + endp = NULL; + else { + if(*endp != '-') + endp = NULL; + else { + pattern = endp + 1; + while(*pattern && ISBLANK(*pattern)) + pattern++; + if(!ISDIGIT(*pattern)) { + endp = NULL; + goto fail; + } + errno = 0; + max_n = strtoul(pattern, &endp, 10); + if(errno) + /* overflow */ + endp = NULL; + else if(*endp == ':') { + pattern = endp + 1; + errno = 0; + step_n = strtoul(pattern, &endp, 10); + if(errno) + /* over/underflow situation */ + endp = NULL; + } + else + step_n = 1; + if(endp && (*endp == ']')) { + pattern = endp + 1; + } + else + endp = NULL; + } + } + + fail: + *posp += (pattern - *patternp); + + if(!endp || !step_n || + (min_n == max_n && step_n != 1) || + (min_n != max_n && (min_n > max_n || step_n > (max_n - min_n)))) + /* the pattern is not well-formed */ + return GLOBERROR("bad range", *posp, CURLE_URL_MALFORMAT); + + /* typecasting to ints are fine here since we make sure above that we + are within 31 bits */ + pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n; + pat->content.NumRange.max_n = max_n; + pat->content.NumRange.step = step_n; + + if(multiply(amount, ((pat->content.NumRange.max_n - + pat->content.NumRange.min_n) / + pat->content.NumRange.step + 1))) + return GLOBERROR("range overflow", *posp, CURLE_URL_MALFORMAT); + } + else + return GLOBERROR("bad range specification", *posp, CURLE_URL_MALFORMAT); + + *patternp = pattern; + return CURLE_OK; +} + +#define MAX_IP6LEN 128 + +static bool peek_ipv6(const char *str, size_t *skip) +{ + /* + * Scan for a potential IPv6 literal. + * - Valid globs contain a hyphen and <= 1 colon. + * - IPv6 literals contain no hyphens and >= 2 colons. + */ + char hostname[MAX_IP6LEN]; + CURLU *u; + char *endbr = strchr(str, ']'); + size_t hlen; + CURLUcode rc; + if(!endbr) + return FALSE; + + hlen = endbr - str + 1; + if(hlen >= MAX_IP6LEN) + return FALSE; + + u = curl_url(); + if(!u) + return FALSE; + + memcpy(hostname, str, hlen); + hostname[hlen] = 0; + + /* ask to "guess scheme" as then it works without a https:// prefix */ + rc = curl_url_set(u, CURLUPART_URL, hostname, CURLU_GUESS_SCHEME); + + curl_url_cleanup(u); + if(!rc) + *skip = hlen; + return rc ? FALSE : TRUE; +} + +static CURLcode glob_parse(struct URLGlob *glob, char *pattern, + size_t pos, unsigned long *amount) +{ + /* processes a literal string component of a URL + special characters '{' and '[' branch to set/range processing functions + */ + CURLcode res = CURLE_OK; + int globindex = 0; /* count "actual" globs */ + + *amount = 1; + + while(*pattern && !res) { + char *buf = glob->glob_buffer; + size_t sublen = 0; + while(*pattern && *pattern != '{') { + if(*pattern == '[') { + /* skip over IPv6 literals and [] */ + size_t skip = 0; + if(!peek_ipv6(pattern, &skip) && (pattern[1] == ']')) + skip = 2; + if(skip) { + memcpy(buf, pattern, skip); + buf += skip; + pattern += skip; + sublen += skip; + continue; + } + break; + } + if(*pattern == '}' || *pattern == ']') + return GLOBERROR("unmatched close brace/bracket", pos, + CURLE_URL_MALFORMAT); + + /* only allow \ to escape known "special letters" */ + if(*pattern == '\\' && + (*(pattern + 1) == '{' || *(pattern + 1) == '[' || + *(pattern + 1) == '}' || *(pattern + 1) == ']') ) { + + /* escape character, skip '\' */ + ++pattern; + ++pos; + } + *buf++ = *pattern++; /* copy character to literal */ + ++pos; + sublen++; + } + if(sublen) { + /* we got a literal string, add it as a single-item list */ + *buf = '\0'; + res = glob_fixed(glob, glob->glob_buffer, sublen); + } + else { + switch (*pattern) { + case '\0': /* done */ + break; + + case '{': + /* process set pattern */ + pattern++; + pos++; + res = glob_set(glob, &pattern, &pos, amount, globindex++); + break; + + case '[': + /* process range pattern */ + pattern++; + pos++; + res = glob_range(glob, &pattern, &pos, amount, globindex++); + break; + } + } + + if(++glob->size >= GLOB_PATTERN_NUM) + return GLOBERROR("too many globs", pos, CURLE_URL_MALFORMAT); + } + return res; +} + +CURLcode glob_url(struct URLGlob **glob, char *url, unsigned long *urlnum, + FILE *error) +{ + /* + * We can deal with any-size, just make a buffer with the same length + * as the specified URL! + */ + struct URLGlob *glob_expand; + unsigned long amount = 0; + char *glob_buffer; + CURLcode res; + + *glob = NULL; + + glob_buffer = malloc(strlen(url) + 1); + if(!glob_buffer) + return CURLE_OUT_OF_MEMORY; + glob_buffer[0] = 0; + + glob_expand = calloc(1, sizeof(struct URLGlob)); + if(!glob_expand) { + Curl_safefree(glob_buffer); + return CURLE_OUT_OF_MEMORY; + } + glob_expand->urllen = strlen(url); + glob_expand->glob_buffer = glob_buffer; + + res = glob_parse(glob_expand, url, 1, &amount); + if(!res) + *urlnum = amount; + else { + if(error && glob_expand->error) { + char text[512]; + const char *t; + if(glob_expand->pos) { + msnprintf(text, sizeof(text), "%s in URL position %zu:\n%s\n%*s^", + glob_expand->error, + glob_expand->pos, url, (int)glob_expand->pos - 1, " "); + t = text; + } + else + t = glob_expand->error; + + /* send error description to the error-stream */ + fprintf(error, "curl: (%d) %s\n", res, t); + } + /* it failed, we cleanup */ + glob_cleanup(glob_expand); + *urlnum = 1; + return res; + } + + *glob = glob_expand; + return CURLE_OK; +} + +void glob_cleanup(struct URLGlob *glob) +{ + size_t i; + int elem; + + if(!glob) + return; + + for(i = 0; i < glob->size; i++) { + if((glob->pattern[i].type == UPTSet) && + (glob->pattern[i].content.Set.elements)) { + for(elem = glob->pattern[i].content.Set.size - 1; + elem >= 0; + --elem) { + Curl_safefree(glob->pattern[i].content.Set.elements[elem]); + } + Curl_safefree(glob->pattern[i].content.Set.elements); + } + } + Curl_safefree(glob->glob_buffer); + Curl_safefree(glob); +} + +CURLcode glob_next_url(char **globbed, struct URLGlob *glob) +{ + struct URLPattern *pat; + size_t i; + size_t len; + size_t buflen = glob->urllen + 1; + char *buf = glob->glob_buffer; + + *globbed = NULL; + + if(!glob->beenhere) + glob->beenhere = 1; + else { + bool carry = TRUE; + + /* implement a counter over the index ranges of all patterns, starting + with the rightmost pattern */ + for(i = 0; carry && (i < glob->size); i++) { + carry = FALSE; + pat = &glob->pattern[glob->size - 1 - i]; + switch(pat->type) { + case UPTSet: + if((pat->content.Set.elements) && + (++pat->content.Set.ptr_s == pat->content.Set.size)) { + pat->content.Set.ptr_s = 0; + carry = TRUE; + } + break; + case UPTCharRange: + pat->content.CharRange.ptr_c = + (char)(pat->content.CharRange.step + + (int)((unsigned char)pat->content.CharRange.ptr_c)); + if(pat->content.CharRange.ptr_c > pat->content.CharRange.max_c) { + pat->content.CharRange.ptr_c = pat->content.CharRange.min_c; + carry = TRUE; + } + break; + case UPTNumRange: + pat->content.NumRange.ptr_n += pat->content.NumRange.step; + if(pat->content.NumRange.ptr_n > pat->content.NumRange.max_n) { + pat->content.NumRange.ptr_n = pat->content.NumRange.min_n; + carry = TRUE; + } + break; + default: + printf("internal error: invalid pattern type (%d)\n", (int)pat->type); + return CURLE_FAILED_INIT; + } + } + if(carry) { /* first pattern ptr has run into overflow, done! */ + return CURLE_OK; + } + } + + for(i = 0; i < glob->size; ++i) { + pat = &glob->pattern[i]; + switch(pat->type) { + case UPTSet: + if(pat->content.Set.elements) { + msnprintf(buf, buflen, "%s", + pat->content.Set.elements[pat->content.Set.ptr_s]); + len = strlen(buf); + buf += len; + buflen -= len; + } + break; + case UPTCharRange: + if(buflen) { + *buf++ = pat->content.CharRange.ptr_c; + *buf = '\0'; + buflen--; + } + break; + case UPTNumRange: + msnprintf(buf, buflen, "%0*lu", + pat->content.NumRange.padlength, + pat->content.NumRange.ptr_n); + len = strlen(buf); + buf += len; + buflen -= len; + break; + default: + printf("internal error: invalid pattern type (%d)\n", (int)pat->type); + return CURLE_FAILED_INIT; + } + } + + *globbed = strdup(glob->glob_buffer); + if(!*globbed) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + +#define MAX_OUTPUT_GLOB_LENGTH (10*1024) + +CURLcode glob_match_url(char **result, char *filename, struct URLGlob *glob) +{ + char numbuf[18]; + char *appendthis = (char *)""; + size_t appendlen = 0; + struct curlx_dynbuf dyn; + + *result = NULL; + + /* We cannot use the glob_buffer for storage since the filename may be + * longer than the URL we use. + */ + curlx_dyn_init(&dyn, MAX_OUTPUT_GLOB_LENGTH); + + while(*filename) { + if(*filename == '#' && ISDIGIT(filename[1])) { + char *ptr = filename; + unsigned long num = strtoul(&filename[1], &filename, 10); + struct URLPattern *pat = NULL; + + if(num && (num < glob->size)) { + unsigned long i; + num--; /* make it zero based */ + /* find the correct glob entry */ + for(i = 0; i<glob->size; i++) { + if(glob->pattern[i].globindex == (int)num) { + pat = &glob->pattern[i]; + break; + } + } + } + + if(pat) { + switch(pat->type) { + case UPTSet: + if(pat->content.Set.elements) { + appendthis = pat->content.Set.elements[pat->content.Set.ptr_s]; + appendlen = + strlen(pat->content.Set.elements[pat->content.Set.ptr_s]); + } + break; + case UPTCharRange: + numbuf[0] = pat->content.CharRange.ptr_c; + numbuf[1] = 0; + appendthis = numbuf; + appendlen = 1; + break; + case UPTNumRange: + msnprintf(numbuf, sizeof(numbuf), "%0*lu", + pat->content.NumRange.padlength, + pat->content.NumRange.ptr_n); + appendthis = numbuf; + appendlen = strlen(numbuf); + break; + default: + fprintf(stderr, "internal error: invalid pattern type (%d)\n", + (int)pat->type); + curlx_dyn_free(&dyn); + return CURLE_FAILED_INIT; + } + } + else { + /* #[num] out of range, use the #[num] in the output */ + filename = ptr; + appendthis = filename++; + appendlen = 1; + } + } + else { + appendthis = filename++; + appendlen = 1; + } + if(curlx_dyn_addn(&dyn, appendthis, appendlen)) + return CURLE_OUT_OF_MEMORY; + } + + if(curlx_dyn_addn(&dyn, "", 0)) + return CURLE_OUT_OF_MEMORY; + +#if defined(MSDOS) || defined(WIN32) + { + char *sanitized; + SANITIZEcode sc = sanitize_file_name(&sanitized, curlx_dyn_ptr(&dyn), + (SANITIZE_ALLOW_PATH | + SANITIZE_ALLOW_RESERVED)); + curlx_dyn_free(&dyn); + if(sc) + return CURLE_URL_MALFORMAT; + *result = sanitized; + return CURLE_OK; + } +#else + *result = curlx_dyn_ptr(&dyn); + return CURLE_OK; +#endif /* MSDOS || WIN32 */ +} diff --git a/contrib/libs/curl/src/tool_urlglob.h b/contrib/libs/curl/src/tool_urlglob.h new file mode 100644 index 0000000000..80c1537f9d --- /dev/null +++ b/contrib/libs/curl/src/tool_urlglob.h @@ -0,0 +1,78 @@ +#ifndef HEADER_CURL_TOOL_URLGLOB_H +#define HEADER_CURL_TOOL_URLGLOB_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +typedef enum { + UPTSet = 1, + UPTCharRange, + UPTNumRange +} URLPatternType; + +struct URLPattern { + URLPatternType type; + int globindex; /* the number of this particular glob or -1 if not used + within {} or [] */ + union { + struct { + char **elements; + int size; + int ptr_s; + } Set; + struct { + char min_c; + char max_c; + char ptr_c; + int step; + } CharRange; + struct { + unsigned long min_n; + unsigned long max_n; + int padlength; + unsigned long ptr_n; + unsigned long step; + } NumRange; + } content; +}; + +/* the total number of globs supported */ +#define GLOB_PATTERN_NUM 100 + +struct URLGlob { + struct URLPattern pattern[GLOB_PATTERN_NUM]; + size_t size; + size_t urllen; + char *glob_buffer; + char beenhere; + const char *error; /* error message */ + size_t pos; /* column position of error or 0 */ +}; + +CURLcode glob_url(struct URLGlob**, char *, unsigned long *, FILE *); +CURLcode glob_next_url(char **, struct URLGlob *); +CURLcode glob_match_url(char **, char *, struct URLGlob *); +void glob_cleanup(struct URLGlob *glob); + +#endif /* HEADER_CURL_TOOL_URLGLOB_H */ diff --git a/contrib/libs/curl/src/tool_util.c b/contrib/libs/curl/src/tool_util.c new file mode 100644 index 0000000000..8d32343fe7 --- /dev/null +++ b/contrib/libs/curl/src/tool_util.c @@ -0,0 +1,137 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#include "tool_util.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#if defined(WIN32) && !defined(MSDOS) + +/* set in win32_init() */ +extern LARGE_INTEGER tool_freq; +extern bool tool_isVistaOrGreater; + +/* In case of bug fix this function has a counterpart in timeval.c */ +struct timeval tvnow(void) +{ + struct timeval now; + if(tool_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */ + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + now.tv_sec = (long)(count.QuadPart / tool_freq.QuadPart); + now.tv_usec = (long)((count.QuadPart % tool_freq.QuadPart) * 1000000 / + tool_freq.QuadPart); + } + else { + /* Disable /analyze warning that GetTickCount64 is preferred */ +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:28159) +#endif + DWORD milliseconds = GetTickCount(); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + + now.tv_sec = (long)(milliseconds / 1000); + now.tv_usec = (long)((milliseconds % 1000) * 1000); + } + return now; +} + +#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) + +struct timeval tvnow(void) +{ + /* + ** clock_gettime() is granted to be increased monotonically when the + ** monotonic clock is queried. Time starting point is unspecified, it + ** could be the system start-up time, the Epoch, or something else, + ** in any case the time starting point does not change once that the + ** system has started up. + */ + struct timeval now; + struct timespec tsnow; + if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) { + now.tv_sec = tsnow.tv_sec; + now.tv_usec = (int)(tsnow.tv_nsec / 1000); + } + /* + ** Even when the configure process has truly detected monotonic clock + ** availability, it might happen that it is not actually available at + ** run-time. When this occurs simply fallback to other time source. + */ +#ifdef HAVE_GETTIMEOFDAY + else + (void)gettimeofday(&now, NULL); +#else + else { + now.tv_sec = time(NULL); + now.tv_usec = 0; + } +#endif + return now; +} + +#elif defined(HAVE_GETTIMEOFDAY) + +struct timeval tvnow(void) +{ + /* + ** gettimeofday() is not granted to be increased monotonically, due to + ** clock drifting and external source time synchronization it can jump + ** forward or backward in time. + */ + struct timeval now; + (void)gettimeofday(&now, NULL); + return now; +} + +#else + +struct timeval tvnow(void) +{ + /* + ** time() returns the value of time in seconds since the Epoch. + */ + struct timeval now; + now.tv_sec = time(NULL); + now.tv_usec = 0; + return now; +} + +#endif + +/* + * Make sure that the first argument is the more recent time, as otherwise + * we'll get a weird negative time-diff back... + * + * Returns: the time difference in number of milliseconds. + */ +long tvdiff(struct timeval newer, struct timeval older) +{ + return (long)(newer.tv_sec-older.tv_sec)*1000+ + (long)(newer.tv_usec-older.tv_usec)/1000; +} diff --git a/contrib/libs/curl/src/tool_util.h b/contrib/libs/curl/src/tool_util.h new file mode 100644 index 0000000000..366afe4a8b --- /dev/null +++ b/contrib/libs/curl/src/tool_util.h @@ -0,0 +1,38 @@ +#ifndef HEADER_CURL_TOOL_UTIL_H +#define HEADER_CURL_TOOL_UTIL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +struct timeval tvnow(void); + +/* + * Make sure that the first argument (t1) is the more recent time and t2 is + * the older time, as otherwise you get a weird negative time-diff back... + * + * Returns: the time difference in number of milliseconds. + */ +long tvdiff(struct timeval t1, struct timeval t2); + +#endif /* HEADER_CURL_TOOL_UTIL_H */ diff --git a/contrib/libs/curl/src/tool_version.h b/contrib/libs/curl/src/tool_version.h new file mode 100644 index 0000000000..ec47821fa6 --- /dev/null +++ b/contrib/libs/curl/src/tool_version.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_VERSION_H +#define HEADER_CURL_TOOL_VERSION_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include <curl/curlver.h> + +#define CURL_NAME "curl" +#define CURL_COPYRIGHT LIBCURL_COPYRIGHT +#define CURL_VERSION "7.85.0" +#define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR +#define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR +#define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH +#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " + +#endif /* HEADER_CURL_TOOL_VERSION_H */ diff --git a/contrib/libs/curl/src/tool_vms.c b/contrib/libs/curl/src/tool_vms.c new file mode 100644 index 0000000000..62a440f4e5 --- /dev/null +++ b/contrib/libs/curl/src/tool_vms.c @@ -0,0 +1,220 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef __VMS + +#if defined(__DECC) && !defined(__VAX) && \ + defined(__CRTL_VER) && (__CRTL_VER >= 70301000) +#include <unixlib.h> +#endif + +#define ENABLE_CURLX_PRINTF +#include "curlx.h" + +#error #include "curlmsg_vms.h" +#include "tool_vms.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void decc$__posix_exit(int __status); +void decc$exit(int __status); + +static int vms_shell = -1; + +/* VMS has a DCL shell and also has Unix shells ported to it. + * When curl is running under a Unix shell, we want it to be as much + * like Unix as possible. + */ +int is_vms_shell(void) +{ + char *shell; + + /* Have we checked the shell yet? */ + if(vms_shell >= 0) + return vms_shell; + + shell = getenv("SHELL"); + + /* No shell, means DCL */ + if(!shell) { + vms_shell = 1; + return 1; + } + + /* Have to make sure some one did not set shell to DCL */ + if(strcmp(shell, "DCL") == 0) { + vms_shell = 1; + return 1; + } + + vms_shell = 0; + return 0; +} + +/* + * VMS has two exit() routines. When running under a Unix style shell, then + * Unix style and the __posix_exit() routine is used. + * + * When running under the DCL shell, then the VMS encoded codes and decc$exit() + * is used. + * + * We can not use exit() or return a code from main() because the actual + * routine called depends on both the compiler version, compile options, and + * feature macro settings, and one of the exit routines is hidden at compile + * time. + * + * Since we want Curl to work properly under the VMS DCL shell and Unix + * shells under VMS, this routine should compile correctly regardless of + * the settings. + */ + +void vms_special_exit(int code, int vms_show) +{ + int vms_code; + + /* The Posix exit mode is only available after VMS 7.0 */ +#if __CRTL_VER >= 70000000 + if(is_vms_shell() == 0) { + decc$__posix_exit(code); + } +#endif + + if(code > CURL_LAST) { /* If CURL_LAST exceeded then */ + vms_code = CURL_LAST; /* curlmsg.h is out of sync. */ + } + else { + vms_code = vms_cond[code] | vms_show; + } + decc$exit(vms_code); +} + +#if defined(__DECC) && !defined(__VAX) && \ + defined(__CRTL_VER) && (__CRTL_VER >= 70301000) + +/* + * 2004-09-19 SMS. + * + * decc_init() + * + * On non-VAX systems, use LIB$INITIALIZE to set a collection of C + * RTL features without using the DECC$* logical name method, nor + * requiring the user to define the corresponding logical names. + */ + +/* Structure to hold a DECC$* feature name and its desired value. */ +struct decc_feat_t { + char *name; + int value; +}; + +/* Array of DECC$* feature names and their desired values. */ +static const struct decc_feat_t decc_feat_array[] = { + /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */ + { "DECC$ARGV_PARSE_STYLE", 1 }, + /* Preserve case for file names on ODS5 disks. */ + { "DECC$EFS_CASE_PRESERVE", 1 }, + /* Enable multiple dots (and most characters) in ODS5 file names, + while preserving VMS-ness of ";version". */ + { "DECC$EFS_CHARSET", 1 }, + /* List terminator. */ + { (char *)NULL, 0 } +}; + +/* Flag to sense if decc_init() was called. */ +static int decc_init_done = -1; + +/* LIB$INITIALIZE initialization function. */ +static void decc_init(void) +{ + int feat_index; + int feat_value; + int feat_value_max; + int feat_value_min; + int i; + int sts; + + /* Set the global flag to indicate that LIB$INITIALIZE worked. */ + decc_init_done = 1; + + /* Loop through all items in the decc_feat_array[]. */ + for(i = 0; decc_feat_array[i].name != NULL; i++) { + + /* Get the feature index. */ + feat_index = decc$feature_get_index(decc_feat_array[i].name); + + if(feat_index >= 0) { + /* Valid item. Collect its properties. */ + feat_value = decc$feature_get_value(feat_index, 1); + feat_value_min = decc$feature_get_value(feat_index, 2); + feat_value_max = decc$feature_get_value(feat_index, 3); + + if((decc_feat_array[i].value >= feat_value_min) && + (decc_feat_array[i].value <= feat_value_max)) { + /* Valid value. Set it if necessary. */ + if(feat_value != decc_feat_array[i].value) { + sts = decc$feature_set_value(feat_index, 1, + decc_feat_array[i].value); + } + } + else { + /* Invalid DECC feature value. */ + printf(" INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n", + feat_value, + feat_value_min, decc_feat_array[i].name, feat_value_max); + } + } + else { + /* Invalid DECC feature name. */ + printf(" UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[i].name); + } + + } +} + +/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */ + +#pragma nostandard + +/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and + other attributes. Note that "nopic" is significant only on VAX. */ +#pragma extern_model save +#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt +const int spare[8] = {0}; +#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt +void (*const x_decc_init)() = decc_init; +#pragma extern_model restore + +/* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */ +#pragma extern_model save +int LIB$INITIALIZE(void); +#pragma extern_model strict_refdef +int dmy_lib$initialize = (int) LIB$INITIALIZE; +#pragma extern_model restore + +#pragma standard + +#endif /* __DECC && !__VAX && __CRTL_VER && __CRTL_VER >= 70301000 */ + +#endif /* __VMS */ diff --git a/contrib/libs/curl/src/tool_vms.h b/contrib/libs/curl/src/tool_vms.h new file mode 100644 index 0000000000..949206dc58 --- /dev/null +++ b/contrib/libs/curl/src/tool_vms.h @@ -0,0 +1,48 @@ +#ifndef HEADER_CURL_TOOL_VMS_H +#define HEADER_CURL_TOOL_VMS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef __VMS + +/* + * Forward-declaration of global variable vms_show defined + * in tool_main.c, used in main() as parameter for function + * vms_special_exit() to allow proper curl tool exiting. + */ +extern int vms_show; + +int is_vms_shell(void); +void vms_special_exit(int code, int vms_show); + +#undef exit +#define exit(__code) vms_special_exit((__code), (0)) + +#define VMS_STS(c,f,e,s) (((c&0xF)<<28)|((f&0xFFF)<<16)|((e&0x1FFF)<3)|(s&7)) +#define VMSSTS_HIDE VMS_STS(1,0,0,0) + +#endif /* __VMS */ + +#endif /* HEADER_CURL_TOOL_VMS_H */ diff --git a/contrib/libs/curl/src/tool_writeout.c b/contrib/libs/curl/src/tool_writeout.c new file mode 100644 index 0000000000..478e8cc46e --- /dev/null +++ b/contrib/libs/curl/src/tool_writeout.c @@ -0,0 +1,439 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" +#include "tool_cfgable.h" +#include "tool_writeout.h" +#include "tool_writeout_json.h" + +#include "memdebug.h" /* keep this as LAST include */ + +static int writeTime(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json); + +static int writeString(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json); + +static int writeLong(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json); + +static int writeOffset(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json); + +struct httpmap { + const char *str; + int num; +}; + +static const struct httpmap http_version[] = { + { "0", CURL_HTTP_VERSION_NONE}, + { "1", CURL_HTTP_VERSION_1_0}, + { "1.1", CURL_HTTP_VERSION_1_1}, + { "2", CURL_HTTP_VERSION_2}, + { "3", CURL_HTTP_VERSION_3}, + { NULL, 0} /* end of list */ +}; + +/* The designated write function should be the same as the CURLINFO return type + with exceptions special cased in the respective function. For example, + http_version uses CURLINFO_HTTP_VERSION which returns the version as a long, + however it is output as a string and therefore is handled in writeString. + + Yes: "http_version": "1.1" + No: "http_version": 1.1 + + Variable names should be in alphabetical order. + */ +static const struct writeoutvar variables[] = { + {"content_type", VAR_CONTENT_TYPE, CURLINFO_CONTENT_TYPE, writeString}, + {"errormsg", VAR_ERRORMSG, CURLINFO_NONE, writeString}, + {"exitcode", VAR_EXITCODE, CURLINFO_NONE, writeLong}, + {"filename_effective", VAR_EFFECTIVE_FILENAME, CURLINFO_NONE, writeString}, + {"ftp_entry_path", VAR_FTP_ENTRY_PATH, CURLINFO_FTP_ENTRY_PATH, writeString}, + {"header_json", VAR_HEADER_JSON, CURLINFO_NONE, NULL}, + {"http_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong}, + {"http_connect", VAR_HTTP_CODE_PROXY, CURLINFO_HTTP_CONNECTCODE, writeLong}, + {"http_version", VAR_HTTP_VERSION, CURLINFO_HTTP_VERSION, writeString}, + {"json", VAR_JSON, CURLINFO_NONE, NULL}, + {"local_ip", VAR_LOCAL_IP, CURLINFO_LOCAL_IP, writeString}, + {"local_port", VAR_LOCAL_PORT, CURLINFO_LOCAL_PORT, writeLong}, + {"method", VAR_EFFECTIVE_METHOD, CURLINFO_EFFECTIVE_METHOD, writeString}, + {"num_connects", VAR_NUM_CONNECTS, CURLINFO_NUM_CONNECTS, writeLong}, + {"num_headers", VAR_NUM_HEADERS, CURLINFO_NONE, writeLong}, + {"num_redirects", VAR_REDIRECT_COUNT, CURLINFO_REDIRECT_COUNT, writeLong}, + {"onerror", VAR_ONERROR, CURLINFO_NONE, NULL}, + {"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT, + CURLINFO_PROXY_SSL_VERIFYRESULT, writeLong}, + {"redirect_url", VAR_REDIRECT_URL, CURLINFO_REDIRECT_URL, writeString}, + {"referer", VAR_REFERER, CURLINFO_REFERER, writeString}, + {"remote_ip", VAR_PRIMARY_IP, CURLINFO_PRIMARY_IP, writeString}, + {"remote_port", VAR_PRIMARY_PORT, CURLINFO_PRIMARY_PORT, writeLong}, + {"response_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong}, + {"scheme", VAR_SCHEME, CURLINFO_SCHEME, writeString}, + {"size_download", VAR_SIZE_DOWNLOAD, CURLINFO_SIZE_DOWNLOAD_T, writeOffset}, + {"size_header", VAR_HEADER_SIZE, CURLINFO_HEADER_SIZE, writeLong}, + {"size_request", VAR_REQUEST_SIZE, CURLINFO_REQUEST_SIZE, writeLong}, + {"size_upload", VAR_SIZE_UPLOAD, CURLINFO_SIZE_UPLOAD_T, writeOffset}, + {"speed_download", VAR_SPEED_DOWNLOAD, CURLINFO_SPEED_DOWNLOAD_T, + writeOffset}, + {"speed_upload", VAR_SPEED_UPLOAD, CURLINFO_SPEED_UPLOAD_T, writeOffset}, + {"ssl_verify_result", VAR_SSL_VERIFY_RESULT, CURLINFO_SSL_VERIFYRESULT, + writeLong}, + {"stderr", VAR_STDERR, CURLINFO_NONE, NULL}, + {"stdout", VAR_STDOUT, CURLINFO_NONE, NULL}, + {"time_appconnect", VAR_APPCONNECT_TIME, CURLINFO_APPCONNECT_TIME_T, + writeTime}, + {"time_connect", VAR_CONNECT_TIME, CURLINFO_CONNECT_TIME_T, writeTime}, + {"time_namelookup", VAR_NAMELOOKUP_TIME, CURLINFO_NAMELOOKUP_TIME_T, + writeTime}, + {"time_pretransfer", VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T, + writeTime}, + {"time_redirect", VAR_REDIRECT_TIME, CURLINFO_REDIRECT_TIME_T, writeTime}, + {"time_starttransfer", VAR_STARTTRANSFER_TIME, CURLINFO_STARTTRANSFER_TIME_T, + writeTime}, + {"time_total", VAR_TOTAL_TIME, CURLINFO_TOTAL_TIME_T, writeTime}, + {"url", VAR_INPUT_URL, CURLINFO_NONE, writeString}, + {"url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString}, + {"urlnum", VAR_URLNUM, CURLINFO_NONE, writeLong}, + {NULL, VAR_NONE, CURLINFO_NONE, NULL} +}; + +static int writeTime(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json) +{ + bool valid = false; + curl_off_t us = 0; + + (void)per; + (void)per_result; + DEBUGASSERT(wovar->writefunc == writeTime); + + if(wovar->ci) { + if(!curl_easy_getinfo(per->curl, wovar->ci, &us)) + valid = true; + } + else { + DEBUGASSERT(0); + } + + if(valid) { + curl_off_t secs = us / 1000000; + us %= 1000000; + + if(use_json) + fprintf(stream, "\"%s\":", wovar->name); + + fprintf(stream, "%" CURL_FORMAT_CURL_OFF_TU + ".%06" CURL_FORMAT_CURL_OFF_TU, secs, us); + } + else { + if(use_json) + fprintf(stream, "\"%s\":null", wovar->name); + } + + return 1; /* return 1 if anything was written */ +} + +static int writeString(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json) +{ + bool valid = false; + const char *strinfo = NULL; + + DEBUGASSERT(wovar->writefunc == writeString); + + if(wovar->ci) { + if(wovar->ci == CURLINFO_HTTP_VERSION) { + long version = 0; + if(!curl_easy_getinfo(per->curl, CURLINFO_HTTP_VERSION, &version)) { + const struct httpmap *m = &http_version[0]; + while(m->str) { + if(m->num == version) { + strinfo = m->str; + valid = true; + break; + } + m++; + } + } + } + else { + if(!curl_easy_getinfo(per->curl, wovar->ci, &strinfo) && strinfo) + valid = true; + } + } + else { + switch(wovar->id) { + case VAR_ERRORMSG: + if(per_result) { + strinfo = per->errorbuffer[0] ? per->errorbuffer : + curl_easy_strerror(per_result); + valid = true; + } + break; + case VAR_EFFECTIVE_FILENAME: + if(per->outs.filename) { + strinfo = per->outs.filename; + valid = true; + } + break; + case VAR_INPUT_URL: + if(per->this_url) { + strinfo = per->this_url; + valid = true; + } + break; + default: + DEBUGASSERT(0); + break; + } + } + + if(valid) { + DEBUGASSERT(strinfo); + if(use_json) { + fprintf(stream, "\"%s\":", wovar->name); + jsonWriteString(stream, strinfo, FALSE); + } + else + fputs(strinfo, stream); + } + else { + if(use_json) + fprintf(stream, "\"%s\":null", wovar->name); + } + + return 1; /* return 1 if anything was written */ +} + +static int writeLong(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json) +{ + bool valid = false; + long longinfo = 0; + + DEBUGASSERT(wovar->writefunc == writeLong); + + if(wovar->ci) { + if(!curl_easy_getinfo(per->curl, wovar->ci, &longinfo)) + valid = true; + } + else { + switch(wovar->id) { + case VAR_NUM_HEADERS: + longinfo = per->num_headers; + valid = true; + break; + case VAR_EXITCODE: + longinfo = per_result; + valid = true; + break; + case VAR_URLNUM: + if(per->urlnum <= INT_MAX) { + longinfo = (long)per->urlnum; + valid = true; + } + break; + default: + DEBUGASSERT(0); + break; + } + } + + if(valid) { + if(use_json) + fprintf(stream, "\"%s\":%ld", wovar->name, longinfo); + else { + if(wovar->id == VAR_HTTP_CODE || wovar->id == VAR_HTTP_CODE_PROXY) + fprintf(stream, "%03ld", longinfo); + else + fprintf(stream, "%ld", longinfo); + } + } + else { + if(use_json) + fprintf(stream, "\"%s\":null", wovar->name); + } + + return 1; /* return 1 if anything was written */ +} + +static int writeOffset(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json) +{ + bool valid = false; + curl_off_t offinfo = 0; + + (void)per; + (void)per_result; + DEBUGASSERT(wovar->writefunc == writeOffset); + + if(wovar->ci) { + if(!curl_easy_getinfo(per->curl, wovar->ci, &offinfo)) + valid = true; + } + else { + DEBUGASSERT(0); + } + + if(valid) { + if(use_json) + fprintf(stream, "\"%s\":", wovar->name); + + fprintf(stream, "%" CURL_FORMAT_CURL_OFF_T, offinfo); + } + else { + if(use_json) + fprintf(stream, "\"%s\":null", wovar->name); + } + + return 1; /* return 1 if anything was written */ +} + +void ourWriteOut(const char *writeinfo, struct per_transfer *per, + CURLcode per_result) +{ + FILE *stream = stdout; + const char *ptr = writeinfo; + bool done = FALSE; + + while(ptr && *ptr && !done) { + if('%' == *ptr && ptr[1]) { + if('%' == ptr[1]) { + /* an escaped %-letter */ + fputc('%', stream); + ptr += 2; + } + else { + /* this is meant as a variable to output */ + char *end; + size_t vlen; + if('{' == ptr[1]) { + int i; + bool match = FALSE; + end = strchr(ptr, '}'); + ptr += 2; /* pass the % and the { */ + if(!end) { + fputs("%{", stream); + continue; + } + vlen = end - ptr; + for(i = 0; variables[i].name; i++) { + if((strlen(variables[i].name) == vlen) && + curl_strnequal(ptr, variables[i].name, vlen)) { + match = TRUE; + switch(variables[i].id) { + case VAR_ONERROR: + if(per_result == CURLE_OK) + /* this isn't error so skip the rest */ + done = TRUE; + break; + case VAR_STDOUT: + stream = stdout; + break; + case VAR_STDERR: + stream = stderr; + break; + case VAR_JSON: + ourWriteOutJSON(stream, variables, per, per_result); + break; + case VAR_HEADER_JSON: + headerJSON(stream, per); + break; + default: + (void)variables[i].writefunc(stream, &variables[i], + per, per_result, false); + break; + } + break; + } + } + if(!match) { + fprintf(stderr, "curl: unknown --write-out variable: '%.*s'\n", + (int)vlen, ptr); + } + ptr = end + 1; /* pass the end */ + } + else if(!strncmp("header{", &ptr[1], 7)) { + ptr += 8; + end = strchr(ptr, '}'); + if(end) { + char hname[256]; /* holds the longest header field name */ + struct curl_header *header; + vlen = end - ptr; + if(vlen < sizeof(hname)) { + memcpy(hname, ptr, vlen); + hname[vlen] = 0; + if(CURLHE_OK == curl_easy_header(per->curl, hname, 0, + CURLH_HEADER, -1, &header)) + fputs(header->value, stream); + } + ptr = end + 1; + } + else + fputs("%header{", stream); + } + else { + /* illegal syntax, then just output the characters that are used */ + fputc('%', stream); + fputc(ptr[1], stream); + ptr += 2; + } + } + } + else if('\\' == *ptr && ptr[1]) { + switch(ptr[1]) { + case 'r': + fputc('\r', stream); + break; + case 'n': + fputc('\n', stream); + break; + case 't': + fputc('\t', stream); + break; + default: + /* unknown, just output this */ + fputc(*ptr, stream); + fputc(ptr[1], stream); + break; + } + ptr += 2; + } + else { + fputc(*ptr, stream); + ptr++; + } + } +} diff --git a/contrib/libs/curl/src/tool_writeout.h b/contrib/libs/curl/src/tool_writeout.h new file mode 100644 index 0000000000..c7cdb9771c --- /dev/null +++ b/contrib/libs/curl/src/tool_writeout.h @@ -0,0 +1,88 @@ +#ifndef HEADER_CURL_TOOL_WRITEOUT_H +#define HEADER_CURL_TOOL_WRITEOUT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#include "tool_operate.h" + +typedef enum { + VAR_NONE, /* must be the first */ + VAR_APPCONNECT_TIME, + VAR_CONNECT_TIME, + VAR_CONTENT_TYPE, + VAR_EFFECTIVE_FILENAME, + VAR_EFFECTIVE_METHOD, + VAR_EFFECTIVE_URL, + VAR_ERRORMSG, + VAR_EXITCODE, + VAR_FTP_ENTRY_PATH, + VAR_HEADER_JSON, + VAR_HEADER_SIZE, + VAR_HTTP_CODE, + VAR_HTTP_CODE_PROXY, + VAR_HTTP_VERSION, + VAR_INPUT_URL, + VAR_JSON, + VAR_LOCAL_IP, + VAR_LOCAL_PORT, + VAR_NAMELOOKUP_TIME, + VAR_NUM_CONNECTS, + VAR_NUM_HEADERS, + VAR_ONERROR, + VAR_PRETRANSFER_TIME, + VAR_PRIMARY_IP, + VAR_PRIMARY_PORT, + VAR_PROXY_SSL_VERIFY_RESULT, + VAR_REDIRECT_COUNT, + VAR_REDIRECT_TIME, + VAR_REDIRECT_URL, + VAR_REFERER, + VAR_REQUEST_SIZE, + VAR_SCHEME, + VAR_SIZE_DOWNLOAD, + VAR_SIZE_UPLOAD, + VAR_SPEED_DOWNLOAD, + VAR_SPEED_UPLOAD, + VAR_SSL_VERIFY_RESULT, + VAR_STARTTRANSFER_TIME, + VAR_STDERR, + VAR_STDOUT, + VAR_TOTAL_TIME, + VAR_URLNUM, + VAR_NUM_OF_VARS /* must be the last */ +} writeoutid; + +struct writeoutvar { + const char *name; + writeoutid id; + CURLINFO ci; + int (*writefunc)(FILE *stream, const struct writeoutvar *wovar, + struct per_transfer *per, CURLcode per_result, + bool use_json); +}; + +void ourWriteOut(const char *writeinfo, struct per_transfer *per, + CURLcode per_result); + +#endif /* HEADER_CURL_TOOL_WRITEOUT_H */ diff --git a/contrib/libs/curl/src/tool_writeout_json.c b/contrib/libs/curl/src/tool_writeout_json.c new file mode 100644 index 0000000000..a36d60c4f1 --- /dev/null +++ b/contrib/libs/curl/src/tool_writeout_json.c @@ -0,0 +1,145 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF + +/* use our own printf() functions */ +#include "curlx.h" +#include "tool_cfgable.h" +#include "tool_writeout_json.h" +#include "tool_writeout.h" + +void jsonWriteString(FILE *stream, const char *in, bool lowercase) +{ + const char *i = in; + const char *in_end = in + strlen(in); + + fputc('\"', stream); + for(; i < in_end; i++) { + switch(*i) { + case '\\': + fputs("\\\\", stream); + break; + case '\"': + fputs("\\\"", stream); + break; + case '\b': + fputs("\\b", stream); + break; + case '\f': + fputs("\\f", stream); + break; + case '\n': + fputs("\\n", stream); + break; + case '\r': + fputs("\\r", stream); + break; + case '\t': + fputs("\\t", stream); + break; + default: + if (*i < 32) { + fprintf(stream, "u%04x", *i); + } + else { + char out = *i; + if(lowercase && (out >= 'A' && out <= 'Z')) + /* do not use tolower() since that's locale specific */ + out |= ('a' - 'A'); + fputc(out, stream); + } + break; + } + } + fputc('\"', stream); +} + +void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[], + struct per_transfer *per, CURLcode per_result) +{ + int i; + + fputs("{", stream); + + for(i = 0; mappings[i].name != NULL; i++) { + if(mappings[i].writefunc && + mappings[i].writefunc(stream, &mappings[i], per, per_result, true)) + fputs(",", stream); + } + + /* The variables are sorted in alphabetical order but as a special case + curl_version (which is not actually a --write-out variable) is last. */ + fprintf(stream, "\"curl_version\":"); + jsonWriteString(stream, curl_version(), FALSE); + fprintf(stream, "}"); +} + +#ifdef _MSC_VER +/* warning C4706: assignment within conditional expression */ +#pragma warning(disable:4706) +#endif + +void headerJSON(FILE *stream, struct per_transfer *per) +{ + struct curl_header *header; + struct curl_header *prev = NULL; + + fputc('{', stream); + while((header = curl_easy_nextheader(per->curl, CURLH_HEADER, -1, + prev))) { + if(prev) + fputs(",\n", stream); + jsonWriteString(stream, header->name, TRUE); + fputc(':', stream); + prev = header; + if(header->amount > 1) { + if(!header->index) { + /* act on the 0-index entry and pull the others in, then output in a + JSON list */ + size_t a = header->amount; + size_t i = 0; + char *name = header->name; + fputc('[', stream); + do { + jsonWriteString(stream, header->value, FALSE); + if(++i >= a) + break; + fputc(',', stream); + if(curl_easy_header(per->curl, name, i, CURLH_HEADER, + -1, &header)) + break; + } while(1); + } + fputc(']', stream); + } + else { + fputc('[', stream); + jsonWriteString(stream, header->value, FALSE); + fputc(']', stream); + } + } + fputs("\n}", stream); +} diff --git a/contrib/libs/curl/src/tool_writeout_json.h b/contrib/libs/curl/src/tool_writeout_json.h new file mode 100644 index 0000000000..d8466051c5 --- /dev/null +++ b/contrib/libs/curl/src/tool_writeout_json.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_TOOL_WRITEOUT_JSON_H +#define HEADER_CURL_TOOL_WRITEOUT_JSON_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" +#include "tool_writeout.h" + +void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[], + struct per_transfer *per, CURLcode per_result); +void headerJSON(FILE *stream, struct per_transfer *per); +void jsonWriteString(FILE *stream, const char *in, bool lowercase); + +#endif /* HEADER_CURL_TOOL_WRITEOUT_H */ diff --git a/contrib/libs/curl/src/tool_xattr.c b/contrib/libs/curl/src/tool_xattr.c new file mode 100644 index 0000000000..b2a509d005 --- /dev/null +++ b/contrib/libs/curl/src/tool_xattr.c @@ -0,0 +1,143 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_FSETXATTR +# include <sys/xattr.h> /* header from libc, not from libattr */ +# define USE_XATTR +#elif (defined(__FreeBSD_version) && (__FreeBSD_version > 500000)) || \ + defined(__MidnightBSD_version) +# include <sys/types.h> +# include <sys/extattr.h> +# define USE_XATTR +#endif + +#include "tool_xattr.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef USE_XATTR + +/* mapping table of curl metadata to extended attribute names */ +static const struct xattr_mapping { + const char *attr; /* name of the xattr */ + CURLINFO info; +} mappings[] = { + /* mappings proposed by + * https://freedesktop.org/wiki/CommonExtendedAttributes/ + */ + { "user.xdg.referrer.url", CURLINFO_REFERER }, + { "user.xdg.origin.url", CURLINFO_EFFECTIVE_URL }, + { "user.mime_type", CURLINFO_CONTENT_TYPE }, + { NULL, CURLINFO_NONE } /* last element, abort here */ +}; + +/* returns TRUE if a new URL is returned, that then needs to be freed */ +/* @unittest: 1621 */ +#ifdef UNITTESTS +bool stripcredentials(char **url); +#else +static +#endif +bool stripcredentials(char **url) +{ + CURLU *u; + CURLUcode uc; + char *nurl; + u = curl_url(); + if(u) { + uc = curl_url_set(u, CURLUPART_URL, *url, 0); + if(uc) + goto error; + + uc = curl_url_set(u, CURLUPART_USER, NULL, 0); + if(uc) + goto error; + + uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); + if(uc) + goto error; + + uc = curl_url_get(u, CURLUPART_URL, &nurl, 0); + if(uc) + goto error; + + curl_url_cleanup(u); + + *url = nurl; + return TRUE; + } + error: + curl_url_cleanup(u); + return FALSE; +} + +/* store metadata from the curl request alongside the downloaded + * file using extended attributes + */ +int fwrite_xattr(CURL *curl, int fd) +{ + int i = 0; + int err = 0; + + /* loop through all xattr-curlinfo pairs and abort on a set error */ + while(err == 0 && mappings[i].attr) { + char *value = NULL; + CURLcode result = curl_easy_getinfo(curl, mappings[i].info, &value); + if(!result && value) { + bool freeptr = FALSE; + if(CURLINFO_EFFECTIVE_URL == mappings[i].info) + freeptr = stripcredentials(&value); + if(value) { +#ifdef HAVE_FSETXATTR_6 + err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0, 0); +#elif defined(HAVE_FSETXATTR_5) + err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0); +#elif defined(__FreeBSD_version) || defined(__MidnightBSD_version) + { + ssize_t rc = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, + mappings[i].attr, value, strlen(value)); + /* FreeBSD's extattr_set_fd returns the length of the extended + attribute */ + err = (rc < 0 ? -1 : 0); + } +#endif + if(freeptr) + curl_free(value); + } + } + i++; + } + + return err; +} +#else +int fwrite_xattr(CURL *curl, int fd) +{ + (void)curl; + (void)fd; + + return 0; +} +#endif diff --git a/contrib/libs/curl/src/tool_xattr.h b/contrib/libs/curl/src/tool_xattr.h new file mode 100644 index 0000000000..8cc0204138 --- /dev/null +++ b/contrib/libs/curl/src/tool_xattr.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_TOOL_XATTR_H +#define HEADER_CURL_TOOL_XATTR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +int fwrite_xattr(CURL *curl, int fd); + +#endif /* HEADER_CURL_TOOL_XATTR_H */ |