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!
This commit is contained in:
Родитель
265bb99382
Коммит
779043f7a3
49
lib/ftp.c
49
lib/ftp.c
|
@ -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,6 +231,7 @@ int Curl_GetFTPResponse(char *buf,
|
|||
interval.tv_sec = timeout;
|
||||
interval.tv_usec = 0;
|
||||
|
||||
if(!ftp->cache)
|
||||
switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
|
||||
case -1: /* select() error, stop reading */
|
||||
error = SELECT_ERROR;
|
||||
|
@ -239,13 +242,30 @@ int Curl_GetFTPResponse(char *buf,
|
|||
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;
|
||||
}
|
||||
}
|
||||
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**/
|
||||
}
|
||||
break;
|
||||
} /* switch */
|
||||
} /* 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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
Загрузка…
Ссылка в новой задаче