out that libcurl didn't deal with large responses from server commands, when
the single response was consisting of multiple lines but of a total size of
16KB or more. Dan Fandrich improved the ftp test script and provided test
case 1006 to repeat the problem, and I fixed the code to make sure this new
test case runs fine.
This commit is contained in:
Daniel Stenberg 2007-08-24 14:00:42 +00:00
Родитель d994fcf2b1
Коммит 7cba40b218
5 изменённых файлов: 116 добавлений и 39 удалений

Просмотреть файл

@ -6,6 +6,14 @@
Changelog
Daniel S (24 August 2007)
- Bug report #1779054 (http://curl.haxx.se/bug/view.cgi?id=1779054) pointed
out that libcurl didn't deal with large responses from server commands, when
the single response was consisting of multiple lines but of a total size of
16KB or more. Dan Fandrich improved the ftp test script and provided test
case 1006 to repeat the problem, and I fixed the code to make sure this new
test case runs fine.
Patrick M (23 August 2007)
- OS/400 port: new files lib/config-os400.h lib/setup-os400.h packages/OS400/*.
See packages/OS400/README.OS400.

Просмотреть файл

@ -45,7 +45,7 @@ This release includes the following bugfixes:
o resume HTTP PUT using Digest authentication
o FTP NOBODY requests on directories sent "SIZE (null)"
o FTP NOBODY request on file crash
o excessively long FTP server response lines
o excessively long FTP server responses and response lines
o file:// upload then FTP:// upload crash
This release includes the following known bugs:

Просмотреть файл

@ -343,7 +343,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
conn->data_prot = 0;
#endif
res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp,
&gotbytes);
&gotbytes);
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
conn->data_prot = prot;
#endif
@ -387,7 +387,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
/* output debug output if that is requested */
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
if(!conn->sec_complete)
if(!conn->sec_complete)
#endif
if(data->set.verbose)
Curl_debug(data, CURLINFO_HEADER_IN,
@ -424,6 +424,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
ftpc->linestart_resp = 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
@ -436,26 +437,45 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
else
return CURLE_OUT_OF_MEMORY; /**BANG**/
}
else if(keepon && (i == gotbytes) && (gotbytes > BUFSIZE/2)) {
/* We got an excessive line without newlines and we need to deal
with it. First, check if it seems to start with a valid status
code and then we keep just that in the line cache. Then throw
away the rest. */
infof(data, "Excessive FTP response line length received, %zd bytes."
" Stripping\n", gotbytes);
if(STATUSCODE(ftpc->linestart_resp)) {
ftpc->cache_size = 4; /* we copy 4 bytes since after the three-digit
number there is a dash or a space and it
is significant */
ftpc->cache = (char *)malloc((int)ftpc->cache_size);
if(ftpc->cache)
memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size);
else
return CURLE_OUT_OF_MEMORY;
else if(keepon) {
int clipamount = 0;
bool restart = FALSE;
if((perline == gotbytes) && (gotbytes > BUFSIZE/2)) {
/* We got an excessive line without newlines and we need to deal
with it. First, check if it seems to start with a valid status
code and then we keep just that in the line cache. Then throw
away the rest. */
infof(data, "Excessive FTP response line length received, %zd bytes."
" Stripping\n", gotbytes);
restart = TRUE;
if(STATUSCODE(ftpc->linestart_resp))
/* we copy 4 bytes since after the three-digit number there is a
dash or a space and it is significant */
clipamount = 4;
}
else if(perline && (ftpc->nread_resp > BUFSIZE/2)) {
/* We got a large chunk of data and there's still trailing data to
take care of, so we put that part in the "cache" and restart */
clipamount = perline;
restart = TRUE;
}
if(restart) {
if(clipamount) {
ftpc->cache_size = clipamount;
ftpc->cache = (char *)malloc((int)ftpc->cache_size);
if(ftpc->cache)
memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size);
else
return CURLE_OUT_OF_MEMORY;
}
/* now reset a few variables to start over nicely from the start of
the big buffer */
ftpc->nread_resp = 0; /* start over from scratch in the buffer */
ptr = ftpc->linestart_resp = buf;
perline = 0;
}
/* now we forget what we read and get a new chunk in the next loop
and append to the small piece we might have put in the cache */
ftpc->nread_resp = 0;
}
} /* there was data */
@ -603,16 +623,16 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
ftpc->cache_size = 0; /* zero the size just in case */
}
else {
int res;
int res;
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
enum protection_level prot = conn->data_prot;
enum protection_level prot = conn->data_prot;
conn->data_prot = 0;
conn->data_prot = 0;
#endif
res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp,
&gotbytes);
res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp,
&gotbytes);
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
conn->data_prot = prot;
conn->data_prot = prot;
#endif
if(res < 0)
/* EWOULDBLOCK */
@ -654,7 +674,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
/* output debug output if that is requested */
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
if(!conn->sec_complete)
if(!conn->sec_complete)
#endif
if(data->set.verbose)
Curl_debug(data, CURLINFO_HEADER_IN,
@ -2538,7 +2558,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
Curl_sec_request_prot(conn, "private");
/* We set private first as default, in case the line below fails to
set a valid level */
Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
if(Curl_sec_login(conn) != 0)
infof(data, "Logging in with password in cleartext!\n");
@ -2673,13 +2693,13 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
case FTP_CCC:
if (ftpcode < 500) {
/* First shut down the SSL layer (note: this call will block) */
result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
/* First shut down the SSL layer (note: this call will block) */
result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
if(result) {
failf(conn->data, "Failed to clear the command channel (CCC)");
return result;
}
if(result) {
failf(conn->data, "Failed to clear the command channel (CCC)");
return result;
}
}
/* Then continue as normal */
@ -3143,8 +3163,8 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature
if(dlen && !ftpc->cwdfail) {
ftpc->prevpath = path;
if(flen)
/* if 'path' is not the whole string */
ftpc->prevpath[dlen]=0; /* terminate */
/* if 'path' is not the whole string */
ftpc->prevpath[dlen]=0; /* terminate */
infof(data, "Remembering we are in dir %s\n", ftpc->prevpath);
}
else {

Просмотреть файл

@ -43,4 +43,4 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
test296 test297 test298 test610 test611 test612 test406 test407 test408 \
test409 test613 test614 test700 test701 test702 test704 test705 test703 \
test706 test707 test350 test351 test352 test353 test289 test540 test354 \
test231 test1000 test1001 test1002 test1003 test1004 test1005
test231 test1000 test1001 test1002 test1003 test1004 test1005 test1006

49
tests/data/test1006 Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны