curl_off_t total_received = 0;
bool is_multiplex = FALSE;
bool rcvd_eagain = FALSE;
+ bool is_eos = FALSE;
result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
if(result)
/* This is where we loop until we have read everything there is to
read or we get a CURLE_AGAIN */
do {
- bool is_eos = FALSE;
size_t bytestoread;
ssize_t nread;
blen = (size_t)nread;
is_eos = (blen == 0);
- if(!blen) {
- /* if we receive 0 or less here, either the data transfer is done or the
- server closed the connection and we bail out from this! */
+ if(!blen && (conn->recv[FIRSTSOCKET] == Curl_cf_recv)) {
+ /* if we receive 0 or less here and the protocol handler did not
+ replace the connection's `recv` callback, either the data transfer
+ is done or the server closed the connection and
+ we bail out from this!
+ With a `recv` replacement, we assume the protocol handler knows
+ what it is doing and a 0-length receive is fine. For example,
+ SFTP downloads of an empty file would show this. See #19165. */
if(is_multiplex)
DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
else
} while(maxloops--);
- if(!Curl_xfer_is_blocked(data) &&
+ if(!is_eos && !Curl_xfer_is_blocked(data) &&
(!rcvd_eagain || data_pending(data, rcvd_eagain))) {
- /* Did not read until EAGAIN or there is still data pending
+ /* Did not read until EAGAIN/EOS or there is still data pending
* in buffers. Mark as read-again via simulated SELECT results. */
Curl_multi_mark_dirty(data);
CURL_TRC_M(data, "sendrecv_dl() no EAGAIN/pending data, mark as dirty");
!(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)))
return CURLE_OK;
- if((data->req.bytecount + data->req.headerbytecount == 0) &&
- conn->bits.reuse &&
- (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))
+ if(conn->bits.reuse &&
+ (data->req.bytecount + data->req.headerbytecount == 0) &&
+ ((!data->req.no_body && !data->req.done) ||
+ (conn->handler->protocol & PROTO_FAMILY_HTTP))
#ifndef CURL_DISABLE_RTSP
&& (data->set.rtspreq != RTSPREQ_RECEIVE)
#endif
struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
(void)dead_connection;
- DEBUGF(infof(data, "SSH DISCONNECT starts now"));
-
- if(sshc && sshc->ssh_session && sshp) {
- /* only if there is a session still around to use! */
- myssh_state(data, sshc, SSH_SFTP_SHUTDOWN);
- result = ssh_block_statemach(data, sshc, sshp, TRUE);
- }
-
- DEBUGF(infof(data, "SSH DISCONNECT is done"));
- if(sshc)
+ if(sshc) {
+ if(sshc->ssh_session && sshp) {
+ /* only if there is a session still around to use! */
+ DEBUGF(infof(data, "SSH DISCONNECT starts now"));
+ myssh_state(data, sshc, SSH_SFTP_SHUTDOWN);
+ result = ssh_block_statemach(data, sshc, sshp, TRUE);
+ DEBUGF(infof(data, "SSH DISCONNECT is done -> %d", result));
+ }
sshc_cleanup(sshc, data, TRUE);
-
+ }
return result;
}
test1556 test1557 test1558 test1559 test1560 test1561 test1562 test1563 \
test1564 test1565 test1566 test1567 test1568 test1569 test1570 test1571 \
test1572 test1573 test1574 test1575 test1576 test1577 test1578 test1579 \
-test1580 test1581 test1582 \
+test1580 test1581 test1582 test1583 \
\
test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
test1598 test1599 test1600 test1601 test1602 test1603 test1604 test1605 \
--- /dev/null
+<testcase>
+<info>
+<keywords>
+SFTP
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+sftp
+</server>
+<precheck>
+%PERL %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir
+</precheck>
+<name>
+SFTP dir and empty file
+</name>
+<command>
+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: --insecure sftp://%HOSTIP:%SSHPORT%SFTP_PWD/%LOGDIR/test%TESTNUMBER.dir/ --next --key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: --insecure sftp://%HOSTIP:%SSHPORT%SFTP_PWD/%LOGDIR/test%TESTNUMBER.dir/emptyfile.txt
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<errorcode>
+0
+</errorcode>
+</verify>
+</testcase>
<reply>
<datacheck>
d????????? N U U N ??? N NN:NN asubdir
+-rw??????? 1 U U 0 Jan 1 2000 emptyfile.txt
-rw??????? 1 U U 37 Jan 1 2000 plainfile.txt
-r-??????? 1 U U 47 Dec 31 2000 rofile.txt
</datacheck>
<reply>
<datacheck>
d????????? N U U N ??? N NN:NN asubdir
+-rw??????? 1 U U 0 Jan 1 2000 emptyfile.txt
-r-??????? 1 U U 37 Jan 1 2000 plainfile.txt
-r-??????? 1 U U 47 Dec 31 2000 rofile.txt
</datacheck>
utime time, timegm(0,0,12,1,0,100), "plainfile.txt";
chmod 0666, "plainfile.txt";
+ open(FILE, ">emptyfile.txt") || errout "$!";
+ binmode FILE;
+ close(FILE);
+ # The mtime is specifically chosen to be an even number so that it can be
+ # represented exactly on a FAT file system.
+ utime time, timegm(0,0,12,1,0,100), "emptyfile.txt";
+ chmod 0666, "emptyfile.txt";
+
open(FILE, ">rofile.txt") || errout "$!";
binmode FILE;
print FILE "Read-only test file to support curl test suite\n";
}
chmod 0666, "$dirname/rofile.txt";
unlink "$dirname/rofile.txt";
+ unlink "$dirname/emptyfile.txt";
unlink "$dirname/plainfile.txt";
rmdir "$dirname/asubdir";