diff options
author | Daniel Stenberg <daniel@haxx.se> | 2001-12-03 13:48:59 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2001-12-03 13:48:59 +0000 |
commit | 779043f7a3847cc9a502487e3df93f601b9adaeb (patch) | |
tree | dc452d029811243d3296deb6189f3e24ecd10520 | |
parent | 265bb993829018e6cac32b9c3f9dd6f2c5c2e662 (diff) |
As Eric Lavigne pointed out, the ftp response reader MUST cache data that
is not dealt with when we find an end-of-response line, as there might be
important stuff even after the correct line. So on subsequent invokes, the
cached data must be used!
-rw-r--r-- | lib/ftp.c | 71 | ||||
-rw-r--r-- | lib/urldata.h | 3 |
2 files changed, 57 insertions, 17 deletions
@@ -197,6 +197,8 @@ int Curl_GetFTPResponse(char *buf, #define SELECT_TIMEOUT 2 int error = SELECT_OK; + struct FTP *ftp = conn->proto.ftp; + if (ftpcode) *ftpcode = 0; /* 0 for errors */ @@ -229,23 +231,41 @@ int Curl_GetFTPResponse(char *buf, interval.tv_sec = timeout; interval.tv_usec = 0; - switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) { - case -1: /* select() error, stop reading */ - error = SELECT_ERROR; - failf(data, "Transfer aborted due to select() error"); - break; - case 0: /* timeout */ - error = SELECT_TIMEOUT; - failf(data, "Transfer aborted due to timeout"); - break; - default: + if(!ftp->cache) + switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) { + case -1: /* select() error, stop reading */ + error = SELECT_ERROR; + failf(data, "Transfer aborted due to select() error"); + break; + case 0: /* timeout */ + error = SELECT_TIMEOUT; + failf(data, "Transfer aborted due to timeout"); + break; + default: + error = SELECT_OK; + break; + } + if(SELECT_OK == error) { /* * This code previously didn't use the kerberos sec_read() code * to read, but when we use Curl_read() it may do so. Do confirm * that this is still ok and then remove this comment! */ - if(CURLE_OK != Curl_read(conn, sockfd, ptr, BUFSIZE-nread, &gotbytes)) + if(ftp->cache) { + /* we had data in the "cache", copy that instead of doing an actual + read */ + memcpy(ptr, ftp->cache, ftp->cache_size); + gotbytes = ftp->cache_size; + free(ftp->cache); /* free the cache */ + ftp->cache = NULL; /* clear the pointer */ + ftp->cache_size = 0; /* zero the size just in case */ + } + else if(CURLE_OK != Curl_read(conn, sockfd, ptr, + BUFSIZE-nread, &gotbytes)) keepon = FALSE; + + if(!keepon) + ; else if(gotbytes <= 0) { keepon = FALSE; error = SELECT_ERROR; @@ -279,20 +299,35 @@ int Curl_GetFTPResponse(char *buf, * line to the start of the buffer and zero terminate, * for old times sake (and krb4)! */ char *meow; - int i; - for(meow=line_start, i=0; meow<ptr; meow++, i++) - buf[i] = *meow; + int n; + for(meow=line_start, n=0; meow<ptr; meow++, n++) + buf[n] = *meow; *meow=0; /* zero terminate */ keepon=FALSE; + line_start = ptr+1; /* advance pointer */ + i++; /* skip this before getting out */ break; } perline=0; /* line starts over here */ line_start = ptr+1; } } - } - break; - } /* switch */ + if(!keepon && (i != gotbytes)) { + /* We found the end of the response lines, but we didn't parse the + full chunk of data we have read from the server. We therefore + need to store the rest of the data to be checked on the next + invoke as it may actually contain another end of response + already! Cleverly figured out by Eric Lavigne in December + 2001. */ + ftp->cache_size = gotbytes - i; + ftp->cache = (char *)malloc(ftp->cache_size); + if(ftp->cache) + memcpy(ftp->cache, line_start, ftp->cache_size); + else + return CURLE_OUT_OF_MEMORY; /**BANG**/ + } + } /* there was data */ + } /* if(no error) */ } /* while there's buffer left and loop is requested */ if(!error) @@ -2028,6 +2063,8 @@ CURLcode Curl_ftp_disconnect(struct connectdata *conn) if(ftp) { if(ftp->entrypath) free(ftp->entrypath); + if(ftp->cache) + free(ftp->cache); } return CURLE_OK; } diff --git a/lib/urldata.h b/lib/urldata.h index 8f12e8705..3a7509dcd 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -175,6 +175,9 @@ struct FTP { char *file; /* decoded file */ char *entrypath; /* the PWD reply when we logged on */ + + char *cache; /* data cache between getresponse()-calls */ + size_t cache_size; /* size of cache in bytes */ }; /**************************************************************************** |