tool_cb_hdr: only truncate etags output when regular file

When sending the output to stdout it cannot truncate.

Add test1619 to verify --etag-save to stdout

Spotted by Codex Security

Closes #21103
This commit is contained in:
Daniel Stenberg 2026-03-26 14:45:37 +01:00
parent e1fdbdd16f
commit d63432d1f8
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
3 changed files with 61 additions and 11 deletions

View File

@ -263,18 +263,23 @@ static size_t save_etag(const char *etag_h, const char *endp,
if(eot >= etag_h) {
size_t etag_length = eot - etag_h + 1;
/*
* Truncate the etag save stream, it can have an existing etag value.
*/
curlx_struct_stat file;
int fd = fileno(etag_save->stream);
if((fd != -1) &&
!curlx_fstat(fd, &file) &&
(S_ISREG(file.st_mode))) {
/*
* Truncate regular files to avoid stale etag content.
*/
#ifdef HAVE_FTRUNCATE
if(ftruncate(fileno(etag_save->stream), 0)) {
return CURL_WRITEFUNC_ERROR;
}
if(ftruncate(fileno(etag_save->stream), 0))
return CURL_WRITEFUNC_ERROR;
#else
if(fseek(etag_save->stream, 0, SEEK_SET)) {
return CURL_WRITEFUNC_ERROR;
}
if(fseek(etag_save->stream, 0, SEEK_SET))
return CURL_WRITEFUNC_ERROR;
#endif
}
fwrite(etag_h, 1, etag_length, etag_save->stream);
/* terminate with newline */

View File

@ -213,8 +213,8 @@ test1580 test1581 test1582 test1583 test1584 test1585 test1586 \
test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
test1598 test1599 test1600 test1601 test1602 test1603 test1604 test1605 \
test1606 test1607 test1608 test1609 test1610 test1611 test1612 test1613 \
test1614 test1615 test1616 test1617 test1618 \
test1620 test1621 test1622 test1623 test1624 test1625 test1626 test1627 \
test1614 test1615 test1616 test1617 test1618 test1619 test1620 test1621 \
test1622 test1623 test1624 test1625 test1626 test1627 \
\
test1630 test1631 test1632 test1633 test1634 test1635 test1636 test1637 \
test1638 \

45
tests/data/test1619 Normal file
View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="US-ASCII"?>
<testcase>
<info>
<keywords>
HTTP
HTTP GET
</keywords>
</info>
<reply>
<data nocheck="yes" crlf="headers">
HTTP/1.1 200 OK
ETag: W/"heyheyhey"
Content-Length: 4
yes
</data>
</reply>
<client>
<server>
http
</server>
<name>
--etag-save to stdout
</name>
<command >
http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O --etag-save -
</command>
</client>
<verify>
<protocol crlf="headers">
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
</protocol>
<stdout>
W/"heyheyhey"
</stdout>
</verify>
</testcase>