On 07/06/15 23:55, Daniel Stenberg wrote:
I would rather consider a way to introduce an EOF flag so that a
callback can actually say "here are the final N bytes of data". Like
for example allowing a callback to OR the return value with 0x20000000
and treat that bit as EOF. Of course that'd break all older libcurls
but would be made to work with a libcurl supporting this! What would
you think about that?
Sorry for the long wait. I finally got around to write a new patch.
As suggested, in the callback the new READ_FUNC_EOF flag (0x20000000)
can be ORed to the return value to signal the EOF to the library.
what do you think?
cheers, Frank
diff --git a/docs/libcurl/opts/CURLOPT_READFUNCTION.3 b/docs/libcurl/opts/CURLOPT_READFUNCTION.3
index edd9bdb..8c4722e 100644
--- a/docs/libcurl/opts/CURLOPT_READFUNCTION.3
+++ b/docs/libcurl/opts/CURLOPT_READFUNCTION.3
@@ -55,6 +55,10 @@ code from the transfer.
The callback can return \fICURL_READFUNC_PAUSE\fP to cause reading from this
connection to pause. See \fIcurl_easy_pause(3)\fP for further details.
+The amount of bytes returned can be masked with the \fICURL_READFUNC_EOF\fP
+flag to signal that the final bytes of the transfer have been written to the
+\fIbuffer\fP and the callback shall not be called again.
+
\fBBugs\fP: when doing TFTP uploads, you must return the exact amount of data
that the callback wants, or it will be considered the final packet by the
server end and the transfer will end there.
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index 95e1ff3..15d82d3 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -708,6 +708,7 @@ CURL_PUSH_DENY 7.44.0
CURL_PUSH_OK 7.44.0
CURL_READFUNC_ABORT 7.12.1
CURL_READFUNC_PAUSE 7.18.0
+CURL_READFUNC_EOF 7.44.0
CURL_REDIR_GET_ALL 7.19.1
CURL_REDIR_POST_301 7.19.1
CURL_REDIR_POST_302 7.19.1
diff --git a/include/curl/curl.h b/include/curl/curl.h
index eab2f6e..c58601d 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -304,6 +304,10 @@ typedef int (*curl_seek_callback)(void *instream,
/* This is a return code for the read callback that, when returned, will
signal libcurl to pause sending data on the current transfer. */
#define CURL_READFUNC_PAUSE 0x10000001
+/* This is a flag that could be added to the return value of the
+ * read callback. This will signal libcurl that the "end of file" has been
+ * reached. */
+#define CURL_READFUNC_EOF 0x20000000
typedef size_t (*curl_read_callback)(char *buffer,
size_t size,
diff --git a/lib/ftp.c b/lib/ftp.c
index fade092..613e3ed 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1676,7 +1676,8 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
passed += actuallyread;
if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
/* this checks for greater-than only to make sure that the
- CURL_READFUNC_ABORT return code still aborts */
+ CURL_READFUNC_EOF flag or CURL_READFUNC_ABORT return code
+ still aborts */
failf(data, "Failed to read data");
return CURLE_FTP_COULDNT_USE_REST;
}
diff --git a/lib/http.c b/lib/http.c
index b9e8047..506a8c6 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -2182,7 +2182,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
passed += actuallyread;
if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
/* this checks for greater-than only to make sure that the
- CURL_READFUNC_ABORT return code still aborts */
+ CURL_READFUNC_EOF flag or CURL_READFUNC_ABORT return code
+ still aborts */
failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
" bytes from the input", passed);
return CURLE_READ_ERROR;
diff --git a/lib/ssh.c b/lib/ssh.c
index f206453..ef65148 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -1743,7 +1743,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
passed += actuallyread;
if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
/* this checks for greater-than only to make sure that the
- CURL_READFUNC_ABORT return code still aborts */
+ CURL_READFUNC_EOF flag or CURL_READFUNC_ABORT return code
+ still aborts */
failf(data, "Failed to read data");
return CURLE_FTP_COULDNT_USE_REST;
}
diff --git a/lib/telnet.c b/lib/telnet.c
index aabf99d..b80b02b 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -1434,6 +1434,11 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
if(result == CURL_READFUNC_PAUSE)
break;
+ if (result & CURL_READFUNC_EOF) {
+ result &= ~CURL_READFUNC_EOF;
+ keepon = FALSE;
+ }
+
if(result == 0) /* no bytes */
break;
@@ -1633,8 +1638,13 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
keepon = FALSE;
break;
}
- if(nread == CURL_READFUNC_PAUSE)
+ if(nread == CURL_READFUNC_PAUSE) {
break;
+ }
+ if (nread & CURL_READFUNC_EOF) {
+ nread &= ~CURL_READFUNC_EOF;
+ keepon = FALSE;
+ }
}
if(nread > 0) {
diff --git a/lib/transfer.c b/lib/transfer.c
index 32e8702..3e07f35 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -94,6 +94,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
struct SessionHandle *data = conn->data;
size_t buffersize = (size_t)bytes;
int nread;
+ int eofdata = FALSE;
#ifdef CURL_DOES_CONVERSIONS
bool sending_http_headers = FALSE;
@@ -109,7 +110,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
if(data->req.upload_chunky) {
/* if chunked Transfer-Encoding */
- buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
+ /* 32bit hex + CRLF + CRLF + "0" + CRLF + CRLF */
+ buffersize -= ( (8 + 2) + (2 + 1 + 2 + 2) );
data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */
}
@@ -144,7 +146,14 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
}
return CURLE_OK; /* nothing was read */
}
- else if((size_t)nread > buffersize) {
+ else if(nread & CURL_READFUNC_EOF) {
+ nread &= ~CURL_READFUNC_EOF;
+ if ( nread > 0 ) {
+ eofdata = TRUE;
+ }
+ }
+
+ if((size_t)nread > buffersize) {
/* the read function returned a too large value */
*nreadp = 0;
failf(data, "read function returned funny value");
@@ -195,6 +204,13 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
/* copy the prefix to the buffer, leaving out the NUL */
memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+ /* if we got the EOF signal also add final zero chunk */
+ if ( eofdata ) {
+ nread += snprintf(data->req.upload_fromhere + nread,
+ (2 + 1 + 2 + 2),
+ "%s%x%s", endofline_native, 0, endofline_native);
+ }
+
/* always append ASCII CRLF to the data */
memcpy(data->req.upload_fromhere + nread,
endofline_network,
@@ -217,7 +233,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
return result;
#endif /* CURL_DOES_CONVERSIONS */
- if((nread - hexlen) == 0)
+ if (eofdata || (nread - hexlen) == 0)
/* mark this as done once this chunk is transferred */
data->req.upload_done = TRUE;
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html