comparison roundup/cgi/client.py @ 4047:e70643990e9c

Support the use of sendfile() for file transfer, if available.
author Stefan Seefeld <stefan@seefeld.name>
date Tue, 17 Feb 2009 04:32:34 +0000
parents 48be910ebda1
children 662cd78df973
comparison
equal deleted inserted replaced
4046:48be910ebda1 4047:e70643990e9c
817 classname, 'content', nodeid): 817 classname, 'content', nodeid):
818 raise Unauthorised, self._("You are not allowed to view " 818 raise Unauthorised, self._("You are not allowed to view "
819 "this file.") 819 "this file.")
820 820
821 mime_type = klass.get(nodeid, 'type') 821 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
823 lmt = klass.get(nodeid, 'activity').timestamp() 843 lmt = klass.get(nodeid, 'activity').timestamp()
824 844
825 self._serve_file(lmt, mime_type, content) 845 self._serve_file(lmt, mime_type, content, filename)
826 846
827 def serve_static_file(self, file): 847 def serve_static_file(self, file):
828 ''' Serve up the file named from the templates dir 848 ''' Serve up the file named from the templates dir
829 ''' 849 '''
830 # figure the filename - try STATIC_FILES, then TEMPLATES dir 850 # figure the filename - try STATIC_FILES, then TEMPLATES dir
851 if file.endswith('.css'): 871 if file.endswith('.css'):
852 mime_type = 'text/css' 872 mime_type = 'text/css'
853 else: 873 else:
854 mime_type = 'text/plain' 874 mime_type = 'text/plain'
855 875
856 # snarf the content 876 self._serve_file(lmt, mime_type, '', filename)
857 f = open(filename, 'rb') 877
858 try: 878 def _serve_file(self, lmt, mime_type, content=None, filename=None):
859 content = f.read()
860 finally:
861 f.close()
862
863 self._serve_file(lmt, mime_type, content)
864
865 def _serve_file(self, lmt, mime_type, content):
866 ''' guts of serve_file() and serve_static_file() 879 ''' guts of serve_file() and serve_static_file()
867 ''' 880 '''
881
882 if not content:
883 length = os.stat(filename)[stat.ST_SIZE]
884 else:
885 length = len(content)
886
868 # spit out headers 887 # spit out headers
869 self.additional_headers['Content-Type'] = mime_type 888 self.additional_headers['Content-Type'] = mime_type
870 self.additional_headers['Content-Length'] = str(len(content)) 889 self.additional_headers['Content-Length'] = str(length)
871 self.additional_headers['Last-Modified'] = rfc822.formatdate(lmt) 890 self.additional_headers['Last-Modified'] = rfc822.formatdate(lmt)
872 891
873 ims = None 892 ims = None
874 # see if there's an if-modified-since... 893 # see if there's an if-modified-since...
875 # XXX see which interfaces set this 894 # XXX see which interfaces set this
882 ims = rfc822.parsedate(ims)[:6] 901 ims = rfc822.parsedate(ims)[:6]
883 lmtt = time.gmtime(lmt)[:6] 902 lmtt = time.gmtime(lmt)[:6]
884 if lmtt <= ims: 903 if lmtt <= ims:
885 raise NotModified 904 raise NotModified
886 905
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
888 927
889 def renderContext(self): 928 def renderContext(self):
890 ''' Return a PageTemplate for the named page 929 ''' Return a PageTemplate for the named page
891 ''' 930 '''
892 name = self.classname 931 name = self.classname
1057 content = content.encode(self.charset, 'xmlcharrefreplace') 1096 content = content.encode(self.charset, 'xmlcharrefreplace')
1058 1097
1059 # and write 1098 # and write
1060 self._socket_op(self.request.wfile.write, content) 1099 self._socket_op(self.request.wfile.write, content)
1061 1100
1101
1062 def setHeader(self, header, value): 1102 def setHeader(self, header, value):
1063 '''Override a header to be returned to the user's browser. 1103 '''Override a header to be returned to the user's browser.
1064 ''' 1104 '''
1065 self.additional_headers[header] = value 1105 self.additional_headers[header] = value
1066 1106

Roundup Issue Tracker: http://roundup-tracker.org/