As Eric Lavigne pointed out, the ftp response reader MUST cache data that
authorDaniel Stenberg <daniel@haxx.se>
Mon, 3 Dec 2001 13:48:59 +0000 (13:48 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 3 Dec 2001 13:48:59 +0000 (13:48 +0000)
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!

lib/ftp.c
lib/urldata.h

index c84c056..7091e9f 100644 (file)
--- a/lib/ftp.c
+++ b/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,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;
 }
index 8f12e87..3a7509d 100644 (file)
@@ -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 */                    
 };
 
 /****************************************************************************