From cc71d352651a0d954227fac62c1395c56b1cff45 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 2 Nov 2021 15:16:18 +0100 Subject: tool_operate: a failed etag save now only fails that transfer When failing to create the output file for saving an etag, only fail that particular single transfer and allow others to follow. In a serial transfer setup, if no transfer at all is done due to them all being skipped because of this error, curl will output an error message and return exit code 26. Added test 369 and 370 to verify. Reported-by: Earnestly on github Ref: #7942 Closes #7945 --- src/tool_operate.c | 146 +++++++++++++++++++++++++----------------------- tests/data/Makefile.inc | 3 +- tests/data/test369 | 47 ++++++++++++++++ tests/data/test370 | 36 ++++++++++++ 4 files changed, 162 insertions(+), 70 deletions(-) create mode 100644 tests/data/test369 create mode 100644 tests/data/test370 diff --git a/src/tool_operate.c b/src/tool_operate.c index 5d24ccb7d..1a1dc6468 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -800,65 +800,13 @@ static CURLcode single_transfer(struct GlobalConfig *global, struct OutStruct *heads; struct OutStruct *etag_save; struct HdrCbData *hdrcbdata = NULL; - CURL *curl = curl_easy_init(); - result = add_per_transfer(&per); - if(result || !curl) { - curl_easy_cleanup(curl); - result = CURLE_OUT_OF_MEMORY; - break; - } - if(state->uploadfile) { - per->uploadfile = strdup(state->uploadfile); - if(!per->uploadfile) { - curl_easy_cleanup(curl); - result = CURLE_OUT_OF_MEMORY; - 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; + struct OutStruct etag_first; + CURL *curl; - /* 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; + /* --etag-save */ + memset(&etag_first, 0, sizeof(etag_first)); + etag_save = &etag_first; + etag_save->stream = stdout; /* --etag-compare */ if(config->etag_compare_file) { @@ -901,21 +849,16 @@ static CURLcode single_transfer(struct GlobalConfig *global, } } - /* --etag-save */ - etag_save = &per->etag_save; - etag_save->stream = stdout; - 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 to open %s\n", config->etag_save_file); - - result = CURLE_WRITE_ERROR; - break; + 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; @@ -930,6 +873,67 @@ static CURLcode single_transfer(struct GlobalConfig *global, } } + curl = curl_easy_init(); + result = add_per_transfer(&per); + if(result || !curl) { + curl_easy_cleanup(curl); + result = CURLE_OUT_OF_MEMORY; + break; + } + if(state->uploadfile) { + per->uploadfile = strdup(state->uploadfile); + if(!per->uploadfile) { + curl_easy_cleanup(curl); + result = CURLE_OUT_OF_MEMORY; + break; + } + } + *added = TRUE; + per->config = config; + per->curl = curl; + per->urlnum = urlnode->num; + per->etag_save = etag_first; /* copy the whole struct */ + + /* 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) @@ -2305,8 +2309,12 @@ static CURLcode serial_transfers(struct GlobalConfig *global, bool added = FALSE; result = create_transfer(global, share, &added); - if(result || !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; diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc index ba171db15..8b89895ca 100644 --- a/tests/data/Makefile.inc +++ b/tests/data/Makefile.inc @@ -60,7 +60,8 @@ test325 test326 test327 test328 test329 test330 test331 test332 test333 \ test334 test335 test336 test337 test338 test339 test340 test341 test342 \ test343 test344 test345 test346 test347 test348 test349 test350 test351 \ test352 test353 test354 test355 test356 test357 test358 test359 test360 \ -test361 test362 test363 test364 test365 test366 test367 test368 \ +test361 test362 test363 test364 test365 test366 test367 test368 test369 \ +test370 \ \ test392 test393 test394 test395 test396 test397 \ \ diff --git a/tests/data/test369 b/tests/data/test369 new file mode 100644 index 000000000..e1e2b32da --- /dev/null +++ b/tests/data/test369 @@ -0,0 +1,47 @@ + + + +HTTP +HTTP GET +etag + + + +# +# Server-side + + +HTTP/1.1 200 OK +Content-Length: 4 +Content-Type: text/html + +hej + + + +# +# Client-side + + +http + + +--etag-save with bad path then working transfer + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER --etag-save log/nowhere/etag%TESTNUMBER --next http://%HOSTIP:%HTTPPORT/%TESTNUMBER --include --output log/curl%TESTNUMBER.out + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + + diff --git a/tests/data/test370 b/tests/data/test370 new file mode 100644 index 000000000..8a5af1e05 --- /dev/null +++ b/tests/data/test370 @@ -0,0 +1,36 @@ + + + +HTTP +HTTP GET +etag + + + +# +# Server-side + + + +# +# Client-side + + +none + + +--etag-save with bad path - no transfer + + +http://%HOSTIP:%NOLISTENPORT/%TESTNUMBER --etag-save log/nowhere/etag%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +26 + + + -- cgit v1.2.1