Skip to content

Commit 56039e6

Browse files
committed
Support the use of sendfile() for file transfer, if available.
1 parent c647804 commit 56039e6

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

roundup/cgi/apache.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ def end_headers(self):
7777
"""NOOP. There aint no such thing as 'end_headers' in mod_python"""
7878
pass
7979

80+
81+
def sendfile(self, filename, offset = 0, len = -1):
82+
"""Send 'filename' to the user."""
83+
84+
return self._req.sendfile(filename, offset, len)
85+
86+
8087
def handler(req):
8188
"""HTTP request handler"""
8289
_options = req.get_options()

roundup/cgi/client.py

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -819,10 +819,30 @@ def serve_file(self, designator, dre=re.compile(r'([^\d]+)(\d+)')):
819819
"this file.")
820820

821821
mime_type = klass.get(nodeid, 'type')
822-
content = klass.get(nodeid, 'content')
822+
823+
# If this object is a file (i.e., an instance of FileClass),
824+
# see if we can find it in the filesystem. If so, we may be
825+
# able to use the more-efficient request.sendfile method of
826+
# sending the file. If not, just get the "content" property
827+
# in the usual way, and use that.
828+
content = None
829+
filename = None
830+
if isinstance(klass, hyperdb.FileClass):
831+
try:
832+
filename = self.db.filename(classname, nodeid)
833+
except AttributeError:
834+
# The database doesn't store files in the filesystem
835+
# and therefore doesn't provide the "filename" method.
836+
pass
837+
except IOError:
838+
# The file does not exist.
839+
pass
840+
if not filename:
841+
content = klass.get(nodeid, 'content')
842+
823843
lmt = klass.get(nodeid, 'activity').timestamp()
824844

825-
self._serve_file(lmt, mime_type, content)
845+
self._serve_file(lmt, mime_type, content, filename)
826846

827847
def serve_static_file(self, file):
828848
''' Serve up the file named from the templates dir
@@ -853,21 +873,20 @@ def serve_static_file(self, file):
853873
else:
854874
mime_type = 'text/plain'
855875

856-
# snarf the content
857-
f = open(filename, 'rb')
858-
try:
859-
content = f.read()
860-
finally:
861-
f.close()
862-
863-
self._serve_file(lmt, mime_type, content)
876+
self._serve_file(lmt, mime_type, '', filename)
864877

865-
def _serve_file(self, lmt, mime_type, content):
878+
def _serve_file(self, lmt, mime_type, content=None, filename=None):
866879
''' guts of serve_file() and serve_static_file()
867880
'''
881+
882+
if not content:
883+
length = os.stat(filename)[stat.ST_SIZE]
884+
else:
885+
length = len(content)
886+
868887
# spit out headers
869888
self.additional_headers['Content-Type'] = mime_type
870-
self.additional_headers['Content-Length'] = str(len(content))
889+
self.additional_headers['Content-Length'] = str(length)
871890
self.additional_headers['Last-Modified'] = rfc822.formatdate(lmt)
872891

873892
ims = None
@@ -884,7 +903,27 @@ def _serve_file(self, lmt, mime_type, content):
884903
if lmtt <= ims:
885904
raise NotModified
886905

887-
self.write(content)
906+
if not self.headers_done:
907+
self.header()
908+
909+
if self.env['REQUEST_METHOD'] == 'HEAD':
910+
return
911+
912+
# If we have a file, and the 'sendfile' method is available,
913+
# we can bypass reading and writing the content into application
914+
# memory entirely.
915+
if filename:
916+
if hasattr(self.request, 'sendfile'):
917+
self._socket_op(self.request.sendfile, filename)
918+
return
919+
f = open(filename, 'rb')
920+
try:
921+
content = f.read()
922+
finally:
923+
f.close()
924+
925+
self._socket_op(self.request.wfile.write, content)
926+
888927

889928
def renderContext(self):
890929
''' Return a PageTemplate for the named page
@@ -1059,6 +1098,7 @@ def write_html(self, content):
10591098
# and write
10601099
self._socket_op(self.request.wfile.write, content)
10611100

1101+
10621102
def setHeader(self, header, value):
10631103
'''Override a header to be returned to the user's browser.
10641104
'''

0 commit comments

Comments
 (0)