From: stefan Date: Tue, 17 Feb 2009 04:32:34 +0000 (+0000) Subject: Support the use of sendfile() for file transfer, if available. X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=b0197c385e46bafec0ae48edfdbc8402b4eae3b4;p=roundup.git Support the use of sendfile() for file transfer, if available. git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4139 57a73879-2fb5-44c3-a270-3262357dd7e2 --- diff --git a/roundup/cgi/apache.py b/roundup/cgi/apache.py index 846b921..10ad723 100644 --- a/roundup/cgi/apache.py +++ b/roundup/cgi/apache.py @@ -77,6 +77,13 @@ class Request(object): """NOOP. There aint no such thing as 'end_headers' in mod_python""" pass + + def sendfile(self, filename, offset = 0, len = -1): + """Send 'filename' to the user.""" + + return self._req.sendfile(filename, offset, len) + + def handler(req): """HTTP request handler""" _options = req.get_options() diff --git a/roundup/cgi/client.py b/roundup/cgi/client.py index d438e3e..28d1cee 100644 --- a/roundup/cgi/client.py +++ b/roundup/cgi/client.py @@ -819,10 +819,30 @@ class Client: "this file.") mime_type = klass.get(nodeid, 'type') - content = klass.get(nodeid, 'content') + + # If this object is a file (i.e., an instance of FileClass), + # see if we can find it in the filesystem. If so, we may be + # able to use the more-efficient request.sendfile method of + # sending the file. If not, just get the "content" property + # in the usual way, and use that. + content = None + filename = None + if isinstance(klass, hyperdb.FileClass): + try: + filename = self.db.filename(classname, nodeid) + except AttributeError: + # The database doesn't store files in the filesystem + # and therefore doesn't provide the "filename" method. + pass + except IOError: + # The file does not exist. + pass + if not filename: + content = klass.get(nodeid, 'content') + lmt = klass.get(nodeid, 'activity').timestamp() - self._serve_file(lmt, mime_type, content) + self._serve_file(lmt, mime_type, content, filename) def serve_static_file(self, file): ''' Serve up the file named from the templates dir @@ -853,21 +873,20 @@ class Client: else: mime_type = 'text/plain' - # snarf the content - f = open(filename, 'rb') - try: - content = f.read() - finally: - f.close() - - self._serve_file(lmt, mime_type, content) + self._serve_file(lmt, mime_type, '', filename) - def _serve_file(self, lmt, mime_type, content): + def _serve_file(self, lmt, mime_type, content=None, filename=None): ''' guts of serve_file() and serve_static_file() ''' + + if not content: + length = os.stat(filename)[stat.ST_SIZE] + else: + length = len(content) + # spit out headers self.additional_headers['Content-Type'] = mime_type - self.additional_headers['Content-Length'] = str(len(content)) + self.additional_headers['Content-Length'] = str(length) self.additional_headers['Last-Modified'] = rfc822.formatdate(lmt) ims = None @@ -884,7 +903,27 @@ class Client: if lmtt <= ims: raise NotModified - self.write(content) + if not self.headers_done: + self.header() + + if self.env['REQUEST_METHOD'] == 'HEAD': + return + + # If we have a file, and the 'sendfile' method is available, + # we can bypass reading and writing the content into application + # memory entirely. + if filename: + if hasattr(self.request, 'sendfile'): + self._socket_op(self.request.sendfile, filename) + return + f = open(filename, 'rb') + try: + content = f.read() + finally: + f.close() + + self._socket_op(self.request.wfile.write, content) + def renderContext(self): ''' Return a PageTemplate for the named page @@ -1059,6 +1098,7 @@ class Client: # and write self._socket_op(self.request.wfile.write, content) + def setHeader(self, header, value): '''Override a header to be returned to the user's browser. '''