@@ -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