curl: return error if etag options are used with multiple URLs

And document it.

Add tests 484 and 485

Fixes #15729
Reported-by: Tamir Duberstein
Closes #15731
This commit is contained in:
Daniel Stenberg 2024-12-12 17:03:59 +01:00
parent 0439499170
commit a300879b63
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
7 changed files with 113 additions and 6 deletions

View File

@ -25,3 +25,5 @@ line with the desired ETag. An empty file is parsed as an empty ETag.
Use the option --etag-save to first save the ETag from a response, and then
use this option to compare against the saved ETag in a subsequent request.
Use this option with a single URL only.

View File

@ -17,6 +17,6 @@ Example:
# `--etag-save`
Save an HTTP ETag to the specified file. An ETag is a caching related header,
usually returned in a response.
usually returned in a response. Use this option with a single URL only.
If no ETag is sent by the server, an empty file is created.

View File

@ -130,6 +130,7 @@ struct OperationConfig {
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 */
size_t num_urls; /* number of URLs added to the list */
#ifndef CURL_DISABLE_IPFS
char *ipfs_gateway;
#endif /* !CURL_DISABLE_IPFS */

View File

@ -1019,7 +1019,8 @@ const struct LongShort *findlongopt(const char *opt)
sizeof(aliases[0]), findarg);
}
static ParameterError parse_url(struct OperationConfig *config,
static ParameterError parse_url(struct GlobalConfig *global,
struct OperationConfig *config,
const char *nextarg)
{
ParameterError err = PARAM_OK;
@ -1050,6 +1051,11 @@ static ParameterError parse_url(struct OperationConfig *config,
/* fill in the URL */
err = getstr(&url->url, nextarg, DENY_BLANK);
url->flags |= GETOUT_URL;
if((++config->num_urls > 1) && (config->etag_save_file ||
config->etag_compare_file)) {
errorf(global, "The etag options only work on a single URL");
return PARAM_BAD_USE;
}
}
return err;
}
@ -1911,7 +1917,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
config->xattr = toggle;
break;
case C_URL: /* --url */
err = parse_url(config, nextarg);
err = parse_url(global, config, nextarg);
break;
case C_FTP_SSL: /* --ftp-ssl */
case C_SSL: /* --ssl */
@ -2549,10 +2555,20 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
config->socks5_auth &= ~CURLAUTH_GSSAPI;
break;
case C_ETAG_SAVE: /* --etag-save */
err = getstr(&config->etag_save_file, nextarg, DENY_BLANK);
if(config->num_urls > 1) {
errorf(global, "The etag options only work on a single URL");
err = PARAM_BAD_USE;
}
else
err = getstr(&config->etag_save_file, nextarg, DENY_BLANK);
break;
case C_ETAG_COMPARE: /* --etag-compare */
err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK);
if(config->num_urls > 1) {
errorf(global, "The etag options only work on a single URL");
err = PARAM_BAD_USE;
}
else
err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK);
break;
case C_CURVES: /* --curves */
err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK);

View File

@ -78,7 +78,7 @@ test444 test445 test446 test447 test448 test449 test450 test451 test452 \
test453 test454 test455 test456 test457 test458 test459 test460 test461 \
test462 test463 test467 test468 test469 test470 test471 test472 test473 \
test474 test475 test476 test477 test478 test479 test480 test481 test482 \
test483 \
test483 test484 test485 \
test490 test491 test492 test493 test494 test495 test496 test497 test498 \
test499 test500 test501 test502 test503 test504 test505 test506 test507 \
test508 test509 test510 test511 test512 test513 test514 test515 test516 \

44
tests/data/test484 Normal file
View File

@ -0,0 +1,44 @@
<testcase>
<info>
<keywords>
HTTP
etags
</keywords>
</info>
#
# Server-side
<reply>
</reply>
#
# Client-side
<client>
<server>
none
</server>
<name>
Use --etag-compare and -save with more than one URL
</name>
<command>
http://example.com/%TESTNUMBER --etag-compare %LOGDIR/etag%TESTNUMBER --etag-save %LOGDIR/etag%TESTNUMBER --url http://example.net/fooo
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<errorcode>
2
</errorcode>
<stderr mode="text">
curl: The etag options only work on a single URL
curl: option --url: is badly used here
%if manual
curl: try 'curl --help' or 'curl --manual' for more information
%else
curl: try 'curl --help' for more information
%endif
</stderr>
</verify>
</testcase>

44
tests/data/test485 Normal file
View File

@ -0,0 +1,44 @@
<testcase>
<info>
<keywords>
HTTP
etags
</keywords>
</info>
#
# Server-side
<reply>
</reply>
#
# Client-side
<client>
<server>
none
</server>
<name>
Use --etag-compare and -save with more than one URL, URLs specified first
</name>
<command>
http://example.com/%TESTNUMBER http://example.net/fooo --etag-save %LOGDIR/etag%TESTNUMBER
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<errorcode>
2
</errorcode>
<stderr mode="text">
curl: The etag options only work on a single URL
curl: option --etag-save: is badly used here
%if manual
curl: try 'curl --help' or 'curl --manual' for more information
%else
curl: try 'curl --help' for more information
%endif
</stderr>
</verify>
</testcase>