From: Stefan Eissing Date: Tue, 6 Aug 2024 09:44:23 +0000 (+0200) Subject: curl: support repeated use of the verbose option; -vv etc X-Git-Tag: curl-8_10_0~353 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=06c5829dab52d612719cf6c5dc165598874a67df;p=thirdparty%2Fcurl.git curl: support repeated use of the verbose option; -vv etc - make mentioning `-v` on the curl command line increase the verbosity of the trace output - related discussion https://github.com/curl/curl/discussions/13810 - make a single -v revert all previous -v+ changes - make --no-verbose also reset all trace configs Closes #13977 --- diff --git a/docs/cmdline-opts/verbose.md b/docs/cmdline-opts/verbose.md index 89226f18c4..7703bc34ad 100644 --- a/docs/cmdline-opts/verbose.md +++ b/docs/cmdline-opts/verbose.md @@ -28,8 +28,28 @@ and a line starting with * means additional info provided by curl. If you only want HTTP headers in the output, --include or --dump-header might be more suitable options. -If you think this option still does not give you enough details, consider using ---trace or --trace-ascii instead. +Since curl 8.10, mentioning this option several times in the same argument +increases the level of the trace output. However, as before, +a single `-v`, `--verbose` or `--no-verbose` reverts any additions by +previous `-vv` again. This means that `-vv -v` is equivalent to `-v`. This +avoids unwanted verbosity when the option is mentioned in the command line +*and* curl config files. + +Using it twice, e.g. `-vv`, outputs time (`--trace-time`) and transfer +ids (`--trace-ids`), as well as enable tracing for all protocols +(`--trace-config protocol`). + +Adding a third verbose outputs transfer content (`--trace-ascii %`) and +enable tracing of more components (`--trace-config read,write,ssl`). + +A forth time adds tracing of all network components. +(`--trace-config network`). + +Any addition of the verbose option after that has no effect. + +If you think this option does not give you the right details, consider using +--trace or --trace-ascii instead. Or use it only once and use `--trace-config` +to trace the specific components you wish to see. Note that verbose output of curl activities and network traffic might contain sensitive data, including usernames, credentials or secret data content. Be diff --git a/docs/libcurl/curl_global_trace.md b/docs/libcurl/curl_global_trace.md index a76462570a..0b0799db39 100644 --- a/docs/libcurl/curl_global_trace.md +++ b/docs/libcurl/curl_global_trace.md @@ -109,6 +109,27 @@ Traces reading of upload data from the application in order to send it to the se Traces writing of download data, received from the server, to the application. +# TRACE GROUPS + +Besides the specific component names there are the following group names +defined: + +## `all` + +## `network` + +All components involved in bare network I/O, including the SSL layer. + +All components that your libcurl is built with. + +## `protocol` + +All components involved in transfer protocols, such as 'ftp' and 'http/2'. + +## `proxy` + +All components involved in use of proxies. + # %PROTOCOLS% # EXAMPLE diff --git a/lib/curl_trc.c b/lib/curl_trc.c index 3ae9517155..a45e07509f 100644 --- a/lib/curl_trc.c +++ b/lib/curl_trc.c @@ -53,6 +53,9 @@ #include "curl_memory.h" #include "memdebug.h" +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif void Curl_debug(struct Curl_easy *data, curl_infotype type, char *ptr, size_t size) @@ -218,58 +221,102 @@ void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...) } #endif /* !CURL_DISABLE_FTP */ -static struct curl_trc_feat *trc_feats[] = { - &Curl_trc_feat_read, - &Curl_trc_feat_write, +#define TRC_CT_NONE (0) +#define TRC_CT_PROTOCOL (1<<(0)) +#define TRC_CT_NETWORK (1<<(1)) +#define TRC_CT_PROXY (1<<(2)) + +struct trc_feat_def { + struct curl_trc_feat *feat; + unsigned int category; +}; + +static struct trc_feat_def trc_feats[] = { + { &Curl_trc_feat_read, TRC_CT_NONE }, + { &Curl_trc_feat_write, TRC_CT_NONE }, #ifndef CURL_DISABLE_FTP - &Curl_trc_feat_ftp, + { &Curl_trc_feat_ftp, TRC_CT_PROTOCOL }, #endif #ifndef CURL_DISABLE_DOH - &Curl_doh_trc, + { &Curl_doh_trc, TRC_CT_NETWORK }, #endif - NULL, }; -static struct Curl_cftype *cf_types[] = { - &Curl_cft_tcp, - &Curl_cft_udp, - &Curl_cft_unix, - &Curl_cft_tcp_accept, - &Curl_cft_happy_eyeballs, - &Curl_cft_setup, +struct trc_cft_def { + struct Curl_cftype *cft; + unsigned int category; +}; + +static struct trc_cft_def trc_cfts[] = { + { &Curl_cft_tcp, TRC_CT_NETWORK }, + { &Curl_cft_udp, TRC_CT_NETWORK }, + { &Curl_cft_unix, TRC_CT_NETWORK }, + { &Curl_cft_tcp_accept, TRC_CT_NETWORK }, + { &Curl_cft_happy_eyeballs, TRC_CT_NETWORK }, + { &Curl_cft_setup, TRC_CT_PROTOCOL }, #ifdef USE_NGHTTP2 - &Curl_cft_nghttp2, + { &Curl_cft_nghttp2, TRC_CT_PROTOCOL }, #endif #ifdef USE_SSL - &Curl_cft_ssl, + { &Curl_cft_ssl, TRC_CT_NETWORK }, #ifndef CURL_DISABLE_PROXY - &Curl_cft_ssl_proxy, + { &Curl_cft_ssl_proxy, TRC_CT_PROXY }, #endif #endif #if !defined(CURL_DISABLE_PROXY) #if !defined(CURL_DISABLE_HTTP) - &Curl_cft_h1_proxy, + { &Curl_cft_h1_proxy, TRC_CT_PROXY }, #ifdef USE_NGHTTP2 - &Curl_cft_h2_proxy, + { &Curl_cft_h2_proxy, TRC_CT_PROXY }, #endif - &Curl_cft_http_proxy, + { &Curl_cft_http_proxy, TRC_CT_PROXY }, #endif /* !CURL_DISABLE_HTTP */ - &Curl_cft_haproxy, - &Curl_cft_socks_proxy, + { &Curl_cft_haproxy, TRC_CT_PROXY }, + { &Curl_cft_socks_proxy, TRC_CT_PROXY }, #endif /* !CURL_DISABLE_PROXY */ #ifdef USE_HTTP3 - &Curl_cft_http3, + { &Curl_cft_http3, TRC_CT_PROTOCOL }, #endif #if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) - &Curl_cft_http_connect, + { &Curl_cft_http_connect, TRC_CT_PROTOCOL }, #endif - NULL, }; +static void trc_apply_level_by_name(const char * const token, int lvl) +{ + size_t i; + + for(i = 0; i < ARRAYSIZE(trc_cfts); ++i) { + if(strcasecompare(token, trc_cfts[i].cft->name)) { + trc_cfts[i].cft->log_level = lvl; + break; + } + } + for(i = 0; i < ARRAYSIZE(trc_feats); ++i) { + if(strcasecompare(token, trc_feats[i].feat->name)) { + trc_feats[i].feat->log_level = lvl; + break; + } + } +} + +static void trc_apply_level_by_category(int category, int lvl) +{ + size_t i; + + for(i = 0; i < ARRAYSIZE(trc_cfts); ++i) { + if(!category || (trc_cfts[i].category & category)) + trc_cfts[i].cft->log_level = lvl; + } + for(i = 0; i < ARRAYSIZE(trc_feats); ++i) { + if(!category || (trc_feats[i].category & category)) + trc_feats[i].feat->log_level = lvl; + } +} + CURLcode Curl_trc_opt(const char *config) { char *token, *tok_buf, *tmp; - size_t i; int lvl; tmp = strdup(config); @@ -291,24 +338,17 @@ CURLcode Curl_trc_opt(const char *config) lvl = CURL_LOG_LVL_INFO; break; } - for(i = 0; cf_types[i]; ++i) { - if(strcasecompare(token, "all")) { - cf_types[i]->log_level = lvl; - } - else if(strcasecompare(token, cf_types[i]->name)) { - cf_types[i]->log_level = lvl; - break; - } - } - for(i = 0; trc_feats[i]; ++i) { - if(strcasecompare(token, "all")) { - trc_feats[i]->log_level = lvl; - } - else if(strcasecompare(token, trc_feats[i]->name)) { - trc_feats[i]->log_level = lvl; - break; - } - } + if(strcasecompare(token, "all")) + trc_apply_level_by_category(TRC_CT_NONE, lvl); + else if(strcasecompare(token, "protocol")) + trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl); + else if(strcasecompare(token, "network")) + trc_apply_level_by_category(TRC_CT_NETWORK, lvl); + else if(strcasecompare(token, "proxy")) + trc_apply_level_by_category(TRC_CT_PROXY, lvl); + else + trc_apply_level_by_name(token, lvl); + token = strtok_r(NULL, ", ", &tok_buf); } free(tmp); diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index e76ab46b0e..1a2e5374e3 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -316,6 +316,7 @@ struct GlobalConfig { bool silent; /* do not show messages, --silent given */ bool noprogress; /* do not show progress bar */ bool isatty; /* Updated internally if output is a tty */ + unsigned char verbosity; /* How verbose we should be */ char *trace_dump; /* file to dump the network trace to */ FILE *trace_stream; bool trace_fopened; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index a55cac44ca..411a349304 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -1029,6 +1029,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ time_t now; bool longopt = FALSE; bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ + size_t nopts = 0; /* options processed in `flag`*/ ParameterError err = PARAM_OK; bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled by using --OPTION or --no-OPTION */ @@ -2490,8 +2491,27 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ cleanarg(clearthis); break; case C_VERBOSE: /* --verbose */ - if(toggle) { - /* the '%' thing here will cause the trace get sent to stderr */ + /* This option is a super-boolean with side effect when applied + * more than once in the same argument flag, like `-vvv`. */ + if(!toggle) { + global->verbosity = 0; + if(set_trace_config(global, "-all")) + err = PARAM_NO_MEM; + global->tracetype = TRACE_NONE; + break; + } + else if(!nopts) { + /* fist `-v` in an argument resets to base verbosity */ + global->verbosity = 0; + if(set_trace_config(global, "-all")) { + err = PARAM_NO_MEM; + break; + } + } + /* the '%' thing here will cause the trace get sent to stderr */ + switch(global->verbosity) { + case 0: + global->verbosity = 1; Curl_safefree(global->trace_dump); global->trace_dump = strdup("%"); if(!global->trace_dump) @@ -2499,13 +2519,30 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ else { if(global->tracetype && (global->tracetype != TRACE_PLAIN)) warnf(global, - "-v, --verbose overrides an earlier trace/verbose option"); + "-v, --verbose overrides an earlier trace option"); global->tracetype = TRACE_PLAIN; } + break; + case 1: + global->verbosity = 2; + if(set_trace_config(global, "ids,time,protocol")) + err = PARAM_NO_MEM; + break; + case 2: + global->verbosity = 3; + global->tracetype = TRACE_ASCII; + if(set_trace_config(global, "ssl,read,write")) + err = PARAM_NO_MEM; + break; + case 3: + global->verbosity = 4; + if(set_trace_config(global, "network")) + err = PARAM_NO_MEM; + break; + default: + /* no effect for now */ + break; } - else - /* verbose is disabled here */ - global->tracetype = TRACE_NONE; break; case C_VERSION: /* --version */ if(toggle) /* --no-version yields no output! */ @@ -2634,7 +2671,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ break; } a = NULL; - + ++nopts; /* processed one option from `flag` input, loop for more */ } while(!longopt && !singleopt && *++parse && !*usedarg && !err); error: