? file_range.patch
? file_ranges.patch
? tests/foo
? tests/out
? tests/data/.test280.swp
? tests/data/test1016
? tests/data/test1017
? tests/data/test1019
? tests/data/test1020
Index: lib/file.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/file.c,v
retrieving revision 1.103
diff -u -r1.103 file.c
--- lib/file.c	8 Dec 2007 22:50:55 -0000	1.103
+++ lib/file.c	11 Jan 2008 11:28:15 -0000
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -70,6 +70,7 @@
 
 #endif
 
+#include "strtoofft.h"
 #include "urldata.h"
 #include <curl/curl.h>
 #include "progress.h"
@@ -119,6 +120,61 @@
   PROT_FILE                             /* protocol */
 };
 
+
+ /*
+  Check if this is a range download, and if so, set the internal variables
+  properly. This code is copied from the FTP implementation and might as
+  well be factored out.
+ */
+static CURLcode file_range(struct connectdata *conn)
+{
+  curl_off_t from, to;
+  curl_off_t totalsize=-1;
+  char *ptr;
+  char *ptr2;
+  struct SessionHandle *data = conn->data;
+
+  if(data->state.use_range && data->state.range) {
+    from=curlx_strtoofft(data->state.range, &ptr, 0);
+    while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
+      ptr++;
+    to=curlx_strtoofft(ptr, &ptr2, 0);
+    if(ptr == ptr2) {
+      /* we didn't get any digit */
+      to=-1;
+    }
+    if((-1 == to) && (from>=0)) {
+      /* X - */
+      data->state.resume_from = from;
+      DEBUGF(infof(data, "RANGE %" FORMAT_OFF_T " to end of file\n",
+                   from));
+    }
+    else if(from < 0) {
+      /* -Y */
+      totalsize = -from;
+      data->req.maxdownload = -from;
+      data->state.resume_from = from;
+      DEBUGF(infof(data, "RANGE the last %" FORMAT_OFF_T " bytes\n",
+                   totalsize));
+    }
+    else {
+      /* X-Y */
+      totalsize = to-from;
+      data->req.maxdownload = totalsize+1; /* include last byte */
+      data->state.resume_from = from;
+      DEBUGF(infof(data, "RANGE from %" FORMAT_OFF_T
+                   " getting %" FORMAT_OFF_T " bytes\n",
+                   from, data->req.maxdownload));
+    }
+    DEBUGF(infof(data, "range-download from %" FORMAT_OFF_T
+                 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
+                 from, to, data->req.maxdownload));
+  }
+  else
+    data->req.maxdownload = -1;
+  return CURLE_OK;
+}
+
 /*
  * file_connect() gets called from Curl_protocol_connect() to allow us to
  * do protocol-specific actions at connect-time.  We emulate a
@@ -434,6 +490,20 @@
     return result;
   }
 
+  /* Check whether file range has been specified */
+  file_range(conn);
+
+  /* Adjust the start offset in case we want to get the N last bytes
+   * of the stream iff the filesize could be determined */
+  if(data->state.resume_from < 0){
+    if(!fstated){
+      failf(data, "Can't get the size of file.");
+      return CURLE_READ_ERROR;
+    }
+    else
+      data->state.resume_from += (curl_off_t)statbuf.st_size;
+  }
+
   if(data->state.resume_from <= expected_size)
     expected_size -= data->state.resume_from;
   else {
@@ -441,6 +511,10 @@
     return CURLE_BAD_DOWNLOAD_RESUME;
   }
 
+  /* A high water mark has been specified so we obey... */
+  if (data->req.maxdownload > 0)
+    expected_size = data->req.maxdownload;
+
   if(fstated && (expected_size == 0))
     return CURLE_OK;
 
@@ -460,15 +534,20 @@
   Curl_pgrsTime(data, TIMER_STARTTRANSFER);
 
   while(res == CURLE_OK) {
-    nread = read(fd, buf, BUFSIZE-1);
+    /* Don't fill a whole buffer if we want less than all data */
+    if (expected_size < BUFSIZE-1)
+      nread = read(fd, buf, expected_size);
+    else
+      nread = read(fd, buf, BUFSIZE-1);
 
     if( nread > 0)
       buf[nread] = 0;
 
-    if(nread <= 0)
+    if (nread <= 0 || expected_size == 0)
       break;
 
     bytecount += nread;
+    expected_size -= nread;
 
     res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
     if(res)

