Commits

visteya  committed f60e861

Change lib.static.serve_file() to use a file generator for requests with Ranges, rather than read entire range into memory. Closes #859.

  • Participants
  • Parent commits 3cb302c

Comments (0)

Files changed (2)

File cherrypy/lib/__init__.py

     input.close()
 
 
+def file_generator_limited(fileobj, count, chunk_size=65536):
+    """Yield the given file object in chunks, stopping after `count`
+    bytes has been emitted.  Default chunk size is 64kB. (Core)
+    """
+    remaining = count
+    while remaining > 0:
+        chunk = fileobj.read(min(chunk_size, remaining))
+        chunklen = len(chunk)
+        if chunklen == 0:
+            return
+        remaining -= chunklen
+        yield chunk
 

File cherrypy/lib/static.py

 import urllib
 
 import cherrypy
-from cherrypy.lib import cptools, http
+from cherrypy.lib import cptools, http, file_generator_limited
 
 
 def serve_file(path, content_type=None, disposition=None, name=None):
             if len(r) == 1:
                 # Return a single-part response.
                 start, stop = r[0]
+                if stop > c_len:
+                    stop = c_len
                 r_len = stop - start
                 response.status = "206 Partial Content"
                 response.headers['Content-Range'] = ("bytes %s-%s/%s" %
                                                        (start, stop - 1, c_len))
                 response.headers['Content-Length'] = r_len
                 bodyfile.seek(start)
-                response.body = bodyfile.read(r_len)
+                response.body = file_generator_limited(bodyfile, r_len)
             else:
                 # Return a multipart/byteranges response.
                 response.status = "206 Partial Content"
                         yield ("\r\nContent-range: bytes %s-%s/%s\r\n\r\n"
                                % (start, stop - 1, c_len))
                         bodyfile.seek(start)
-                        yield bodyfile.read(stop - start)
+                        for chunk in file_generator_limited(bodyfile, stop-start):
+                            yield chunk
                         yield "\r\n"
                     # Final boundary
                     yield "--" + boundary + "--"