Added more verbose "warning" messages to the curl client for cases where it

fails to open/read files etc to help users diagnose why it doesn't do what
you'd expect it to. Converted lots of old messages to use the new generic
function I wrote for this purpose.
This commit is contained in:
Daniel Stenberg 2005-08-15 21:48:28 +00:00
parent 35110eca73
commit d9ca9154d1
1 changed files with 215 additions and 161 deletions

View File

@ -243,6 +243,161 @@ static int ftruncate64 (int fd, curl_off_t where)
#define ftruncate(fd,where) ftruncate64(fd,where)
#endif
typedef enum {
TRACE_BIN, /* tcpdump inspired look */
TRACE_ASCII, /* like *BIN but without the hex output */
TRACE_PLAIN /* -v/--verbose type */
} trace;
struct Configurable {
bool remote_time;
char *random_file;
char *egd_file;
char *useragent;
char *cookie; /* single line with specified cookies */
char *cookiejar; /* write to this file */
char *cookiefile; /* read from this file */
bool cookiesession; /* new session? */
bool encoding; /* Accept-Encoding please */
long authtype; /* auth bitmask */
bool use_resume;
bool resume_from_current;
bool disable_epsv;
bool disable_eprt;
curl_off_t resume_from;
char *postfields;
long postfieldsize;
char *referer;
long timeout;
long connecttimeout;
long maxredirs;
curl_off_t max_filesize;
char *headerfile;
char *ftpport;
char *iface;
unsigned short porttouse;
char *range;
long low_speed_limit;
long low_speed_time;
bool showerror;
char *userpwd;
char *proxyuserpwd;
char *proxy;
bool proxytunnel;
long conf;
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 */
char *cipher_list;
char *cert;
char *cert_type;
char *cacert;
char *capath;
char *key;
char *key_type;
char *key_passwd;
char *engine;
bool list_engines;
bool crlf;
char *customrequest;
char *krb4level;
char *trace_dump; /* file to dump the network trace to, or NULL */
FILE *trace_stream;
bool trace_fopened;
trace tracetype;
bool tracetime; /* include timestamp? */
long httpversion;
bool progressmode;
bool nobuffer;
bool globoff;
bool use_httpget;
bool insecure_ok; /* set TRUE to allow insecure SSL connects */
bool create_dirs;
bool ftp_create_dirs;
bool proxyntlm;
bool proxydigest;
bool proxybasic;
bool proxyanyauth;
char *writeout; /* %-styled format string to output */
bool writeenv; /* write results to environment, if available */
FILE *errors; /* if stderr redirect is requested */
bool errors_fopened;
struct curl_slist *quote;
struct curl_slist *postquote;
struct curl_slist *prequote;
long ssl_version;
long ip_version;
curl_TimeCond timecond;
time_t condtime;
struct curl_slist *headers;
struct curl_httppost *httppost;
struct curl_httppost *last_post;
struct curl_slist *telnet_options;
HttpReq httpreq;
/* for bandwidth limiting features: */
curl_off_t sendpersecond; /* send to peer */
curl_off_t recvpersecond; /* receive from peer */
struct timeval lastsendtime;
size_t lastsendsize;
struct timeval lastrecvtime;
size_t lastrecvsize;
bool ftp_ssl;
char *socks5proxy;
bool tcp_nodelay;
long req_retry; /* number of retries */
long retry_delay; /* delay between retries (in seconds) */
long retry_maxtime; /* maximum time to keep retrying */
char *tp_url; /* third party URL */
char *tp_user; /* third party userpwd */
struct curl_slist *tp_quote;
struct curl_slist *tp_postquote;
struct curl_slist *tp_prequote;
char *ftp_account; /* for ACCT */
};
#define WARN_PREFIX "Warning: "
#define WARN_TEXTWIDTH (79 - strlen(WARN_PREFIX))
/* produce this text message to the user unless mute was selected */
static void warnf(struct Configurable *config, const char *fmt, ...)
{
if(!(config->conf & CONF_MUTE)) {
va_list ap;
int len;
char *ptr;
char print_buffer[256];
va_start(ap, fmt);
va_start(ap, fmt);
len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
va_end(ap);
ptr = print_buffer;
while(len > 0) {
fputs(WARN_PREFIX, config->errors);
if(len > (int)WARN_TEXTWIDTH) {
int cut = WARN_TEXTWIDTH-1;
while(!isspace(ptr[cut]) && cut) {
cut--;
}
fwrite(ptr, cut + 1, 1, config->errors);
fputs("\n", config->errors);
ptr += cut+1; /* skip the space too */
len -= cut;
}
else {
fputs(ptr, config->errors);
len = 0;
}
}
}
}
/*
* This is the main global constructor for the app. Call this before
* _any_ libcurl usage. If this fails, *NO* libcurl functions may be
@ -262,14 +417,15 @@ static void main_free(void)
curl_global_cleanup();
}
static int SetHTTPrequest(HttpReq req, HttpReq *store)
static int SetHTTPrequest(struct Configurable *config,
HttpReq req, HttpReq *store)
{
if((*store == HTTPREQ_UNSPEC) ||
(*store == req)) {
*store = req;
return 0;
}
fprintf(stderr, "You can only select one HTTP request!\n");
warnf(config, "You can only select one HTTP request!\n");
return 1;
}
@ -306,12 +462,6 @@ struct getout {
#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
typedef enum {
TRACE_BIN, /* tcpdump inspired look */
TRACE_ASCII, /* like *BIN but without the hex output */
TRACE_PLAIN /* -v/--verbose type */
} trace;
static void help(void)
{
int i;
@ -450,115 +600,6 @@ struct LongShort {
bool extraparam;
};
struct Configurable {
bool remote_time;
char *random_file;
char *egd_file;
char *useragent;
char *cookie; /* single line with specified cookies */
char *cookiejar; /* write to this file */
char *cookiefile; /* read from this file */
bool cookiesession; /* new session? */
bool encoding; /* Accept-Encoding please */
long authtype; /* auth bitmask */
bool use_resume;
bool resume_from_current;
bool disable_epsv;
bool disable_eprt;
curl_off_t resume_from;
char *postfields;
long postfieldsize;
char *referer;
long timeout;
long connecttimeout;
long maxredirs;
curl_off_t max_filesize;
char *headerfile;
char *ftpport;
char *iface;
unsigned short porttouse;
char *range;
long low_speed_limit;
long low_speed_time;
bool showerror;
char *userpwd;
char *proxyuserpwd;
char *proxy;
bool proxytunnel;
long conf;
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 */
char *cipher_list;
char *cert;
char *cert_type;
char *cacert;
char *capath;
char *key;
char *key_type;
char *key_passwd;
char *engine;
bool list_engines;
bool crlf;
char *customrequest;
char *krb4level;
char *trace_dump; /* file to dump the network trace to, or NULL */
FILE *trace_stream;
bool trace_fopened;
trace tracetype;
bool tracetime; /* include timestamp? */
long httpversion;
bool progressmode;
bool nobuffer;
bool globoff;
bool use_httpget;
bool insecure_ok; /* set TRUE to allow insecure SSL connects */
bool create_dirs;
bool ftp_create_dirs;
bool proxyntlm;
bool proxydigest;
bool proxybasic;
bool proxyanyauth;
char *writeout; /* %-styled format string to output */
bool writeenv; /* write results to environment, if available */
FILE *errors; /* if stderr redirect is requested */
bool errors_fopened;
struct curl_slist *quote;
struct curl_slist *postquote;
struct curl_slist *prequote;
long ssl_version;
long ip_version;
curl_TimeCond timecond;
time_t condtime;
struct curl_slist *headers;
struct curl_httppost *httppost;
struct curl_httppost *last_post;
struct curl_slist *telnet_options;
HttpReq httpreq;
/* for bandwidth limiting features: */
curl_off_t sendpersecond; /* send to peer */
curl_off_t recvpersecond; /* receive from peer */
struct timeval lastsendtime;
size_t lastsendsize;
struct timeval lastrecvtime;
size_t lastrecvsize;
bool ftp_ssl;
char *socks5proxy;
bool tcp_nodelay;
long req_retry; /* number of retries */
long retry_delay; /* delay between retries (in seconds) */
long retry_maxtime; /* maximum time to keep retrying */
char *tp_url; /* third party URL */
char *tp_user; /* third party userpwd */
struct curl_slist *tp_quote;
struct curl_slist *tp_postquote;
struct curl_slist *tp_prequote;
char *ftp_account; /* for ACCT */
};
/* global variable to hold info about libcurl */
static curl_version_info_data *curlinfo;
@ -814,7 +855,8 @@ static void list_engines (const struct curl_slist *engines)
#define FORM_FILE_SEPARATOR ','
#define FORM_TYPE_SEPARATOR ';'
static int formparse(char *input,
static int formparse(struct Configurable *config,
char *input,
struct curl_httppost **httppost,
struct curl_httppost **last_post,
bool literal_value)
@ -890,7 +932,7 @@ static int formparse(char *input,
/* verify that this is a fine type specifier */
if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
major, minor)) {
fprintf(stderr, "Illegally formatted content-type field!\n");
warnf(config, "Illegally formatted content-type field!\n");
free(contents);
FreeMultiInfo (multi_start);
return 2; /* illegal content-type syntax! */
@ -939,7 +981,7 @@ static int formparse(char *input,
if (!AddMultiFiles (contp, type, filename, &multi_start,
&multi_current)) {
fprintf(stderr, "Error building form post!\n");
warnf(config, "Error building form post!\n");
free(contents);
FreeMultiInfo (multi_start);
return 3;
@ -976,7 +1018,7 @@ static int formparse(char *input,
if (curl_formadd(httppost, last_post,
CURLFORM_COPYNAME, name,
CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
fprintf(stderr, "curl_formadd failed!\n");
warnf(config, "curl_formadd failed!\n");
free(forms);
free(contents);
return 5;
@ -1008,8 +1050,8 @@ static int formparse(char *input,
if (curl_formadd(httppost, last_post,
CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
fprintf(stderr, "curl_formadd failed, possibly the file %s is bad!\n",
contp+1);
warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
contp+1);
free(contents);
return 6;
}
@ -1021,7 +1063,7 @@ static int formparse(char *input,
info[i].option = CURLFORM_END;
if (curl_formadd(httppost, last_post,
CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
fprintf(stderr, "curl_formadd failed!\n");
warnf(config, "curl_formadd failed!\n");
free(contents);
return 7;
}
@ -1030,7 +1072,7 @@ static int formparse(char *input,
}
else {
fprintf(stderr, "Illegally formatted input field!\n");
warnf(config, "Illegally formatted input field!\n");
return 1;
}
free(contents);
@ -1387,9 +1429,6 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
}
*usedarg = FALSE; /* default is that we don't use the arg */
#if 0
fprintf(stderr, "OPTION: %c %s\n", letter, nextarg?nextarg:"<null>");
#endif
if(hit < 0) {
for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
if(letter == aliases[j].letter[0]) {
@ -1533,8 +1572,13 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
case 'v': /* --stderr */
if(strcmp(nextarg, "-")) {
config->errors = fopen(nextarg, "wt");
config->errors_fopened = TRUE;
FILE *newfile = fopen(nextarg, "wt");
if(!config->errors)
warnf(config, "Failed to open %s!\n", nextarg);
else {
config->errors = newfile;
config->errors_fopened = TRUE;
}
}
else
config->errors = stdout;
@ -1742,8 +1786,12 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
if(curlx_strequal("-", nextarg))
file = stdin;
else
else {
file = fopen(nextarg, "rb");
if(!file)
warnf(config, "Couldn't read data from file \"%s\", this makes "
"an empty POST.\n", nextarg);
}
if(subletter == 'b') /* forced binary */
postdata = file2memory(file, &config->postfieldsize);
@ -1863,12 +1911,13 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
case 'F':
/* "form data" simulation, this is a little advanced so lets do our best
to sort this out slowly and carefully */
if(formparse(nextarg,
if(formparse(config,
nextarg,
&config->httppost,
&config->last_post,
subletter=='s')) /* 's' means literal string */
return PARAM_BAD_USE;
if(SetHTTPrequest(HTTPREQ_POST, &config->httpreq))
if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
return PARAM_BAD_USE;
break;
@ -1904,13 +1953,13 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
(config->conf&(CONF_HEADER|CONF_NOBODY)) ) {
/* one of them weren't set, set both */
config->conf |= (CONF_HEADER|CONF_NOBODY);
if(SetHTTPrequest(HTTPREQ_HEAD, &config->httpreq))
if(SetHTTPrequest(config, HTTPREQ_HEAD, &config->httpreq))
return PARAM_BAD_USE;
}
else {
/* both were set, clear both */
config->conf &= ~(CONF_HEADER|CONF_NOBODY);
if(SetHTTPrequest(HTTPREQ_GET, &config->httpreq))
if(SetHTTPrequest(config, HTTPREQ_GET, &config->httpreq))
return PARAM_BAD_USE;
}
break;
@ -1943,8 +1992,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
hugehelp();
return PARAM_HELP_REQUESTED;
#else
fprintf(stderr,
"curl: built-in manual was disabled at build-time!\n");
warnf(config,
"built-in manual was disabled at build-time!\n");
return PARAM_OPTION_UNKNOWN;
#endif
case 'n':
@ -2157,6 +2206,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
else
file = fopen(nextarg, "r");
config->writeout = file2string(file);
if(!config->writeout)
warnf(config, "Failed to read %s", file);
if(file && (file != stdin))
fclose(file);
}
@ -2212,11 +2263,10 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
if(-1 == stat(nextarg, &statbuf)) {
/* failed, remove time condition */
config->timecond = CURL_TIMECOND_NONE;
if(!(config->conf & CONF_MUTE))
fprintf(stderr,
"Warning: Illegal date format for -z/--timecond and not "
"a file name.\n"
" See curl_getdate(3) for valid date syntax.\n");
warnf(config,
"Illegal date format for -z/--timecond (and not "
"a file name). Disabling time condition. "
"See curl_getdate(3) for valid date syntax.\n");
}
else {
/* pull the time out from the file */
@ -2429,8 +2479,8 @@ static void parseconfig(const char *filename,
}
if(PARAM_HELP_REQUESTED != res) {
const char *reason = param2text(res);
fprintf(stderr, "%s:%d: warning: '%s' %s\n",
filename, lineno, option, reason);
warnf(config, "%s:%d: warning: '%s' %s\n",
filename, lineno, option, reason);
}
}
@ -2493,8 +2543,10 @@ static int my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
if(out && !out->stream) {
/* open file for writing */
out->stream=fopen(out->filename, "wb");
if(!out->stream)
if(!out->stream) {
warnf(config, "Failed to create the file %s\n", out->filename);
return -1; /* failure */
}
}
if(config->recvpersecond) {
@ -3241,14 +3293,15 @@ operate(struct Configurable *config, int argc, char *argv[])
httpgetfields = strdup(config->postfields);
free(config->postfields);
config->postfields = NULL;
if(SetHTTPrequest((config->conf&CONF_NOBODY?HTTPREQ_HEAD:HTTPREQ_GET),
if(SetHTTPrequest(config,
(config->conf&CONF_NOBODY?HTTPREQ_HEAD:HTTPREQ_GET),
&config->httpreq)) {
free(httpgetfields);
return PARAM_BAD_USE;
}
}
else {
if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
return PARAM_BAD_USE;
}
}
@ -3415,7 +3468,7 @@ operate(struct Configurable *config, int argc, char *argv[])
free(storefile);
if(!outfile) {
/* bad globbing */
fprintf(stderr, "bad output glob!\n");
warnf(config, "bad output glob!\n");
free(url);
res = CURLE_FAILED_INIT;
break;
@ -3909,19 +3962,18 @@ operate(struct Configurable *config, int argc, char *argv[])
}
if(retry) {
if(!(config->conf&CONF_MUTE)) {
static const char * const m[]={NULL,
"timeout",
"HTTP error",
"FTP error"
};
fprintf(stderr, "Transient problem: %s\n"
"Will retry in %ld seconds. "
"%ld retries left.\n",
m[retry],
retry_sleep/1000,
retry_numretries);
}
static const char * const m[]={NULL,
"timeout",
"HTTP error",
"FTP error"
};
warnf(config, "Transient problem: %s "
"Will retry in %ld seconds. "
"%ld retries left.\n",
m[retry],
retry_sleep/1000,
retry_numretries);
go_sleep(retry_sleep);
retry_numretries--;
if(!config->retry_delay) {
@ -4135,6 +4187,8 @@ int main(int argc, char *argv[])
struct Configurable config;
memset(&config, 0, sizeof(struct Configurable));
config.errors = stderr; /* default errors to stderr */
checkfds();
res = operate(&config, argc, argv);