Index: file.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/file.inc,v
retrieving revision 1.102
diff -u -p -r1.102 file.inc
--- file.inc	2 Jul 2007 14:41:35 -0000	1.102
+++ file.inc	11 Jul 2007 08:48:50 -0000
@@ -799,10 +799,53 @@ function file_transfer($source, $headers
 
   $source = file_create_path($source);
 
-  // Transfer file in 1024 byte chunks to save memory usage.
   if ($fd = fopen($source, 'rb')) {
-    while (!feof($fd)) {
-      print fread($fd, 1024);
+    // Tell client that we accept byte ranges.
+    drupal_set_header('Accept-Ranges: bytes');
+    // Get file size.
+    $filesize = filesize($source);
+    $end_file = $filesize - 1;
+    // Is this a partial request?
+    if (isset($_SERVER['HTTP_RANGE'])) {
+      preg_match('/^bytes=(\S+)$/i', $_SERVER['HTTP_RANGE'], $ranges);
+      $ranges = explode(',', array_pop($ranges));
+      foreach ($ranges as $key => $range) {
+        if (substr($range, 0, 1) == '-') {
+          $ranges[$key] = array(
+            'from' => max(0, $end_file + $range),
+            'to' => $end_file,
+          );
+        }
+        elseif (substr_count($range, '-') == 1) {
+          $range = explode('-', $range);
+          if ($range[0] < min($range[1], $end_file)) {
+            $ranges[$key] = array(
+              'from' => $range[0],
+              'to' => min($range[1], $end_file),
+            );
+          }
+        }
+        else {
+          unset($ranges[$key]);
+        }
+      }
+      if (!empty($ranges)) {
+        drupal_set_header('HTTP/1.1 206 Partial Content');
+        foreach ($ranges as $range) {
+          // Move file pointer.
+          fseek($fd, $range['from']);
+          drupal_set_header(sprintf('Content-Range: bytes %d-%d/%d', $range['from'], $range['to'], $filesize));
+          $length = $range['to'] + 1 - $range['from'];
+          file_chunks($fd, $length);
+        }
+      }
+      else {
+        drupal_set_header('416 Requested Range Not Satisfiable');
+      }
+    }
+    else {
+      $length = $filesize;
+      file_chunks($fd, $length);
     }
     fclose($fd);
   }
@@ -813,6 +856,18 @@ function file_transfer($source, $headers
 }
 
 /**
+ * Transfer file in 1024 byte chunks to save memory.
+ */
+function file_chunks($fd, $length) {
+  drupal_set_header('Content-Length: '. $length);
+  while ($length > 0) {
+    $read = min(1024, $length);
+    print fread($fd, $read);
+    $length -= $read;
+  }
+}
+
+/**
  * Call modules that implement hook_file_download() to find out if a file is
  * accessible and what headers it should be transferred with. If a module
  * returns -1 drupal_access_denied() will be returned. If one or more modules
