comparison roundup/cgi/client.py @ 3760:b8f52d030f1a

ignore common network errors, like "Connection reset by peer" catch socket errors when sending http headers.
author Alexander Smishlajev <a1s@users.sourceforge.net>
date Wed, 15 Nov 2006 06:27:15 +0000
parents a2d22d0de0bc
children aef19fff38dd
comparison
equal deleted inserted replaced
3759:3a4cce7e77fb 3760:b8f52d030f1a
1 # $Id: client.py,v 1.228 2006-11-09 00:36:21 richard Exp $ 1 # $Id: client.py,v 1.229 2006-11-15 06:27:15 a1s Exp $
2 2
3 """WWW request handler (also used in the stand-alone server). 3 """WWW request handler (also used in the stand-alone server).
4 """ 4 """
5 __docformat__ = 'restructuredtext' 5 __docformat__ = 'restructuredtext'
6 6
106 FV_ERROR_MESSAGE = re.compile(r'[@:]error_message') 106 FV_ERROR_MESSAGE = re.compile(r'[@:]error_message')
107 107
108 # Note: index page stuff doesn't appear here: 108 # Note: index page stuff doesn't appear here:
109 # columns, sort, sortdir, filter, group, groupdir, search_text, 109 # columns, sort, sortdir, filter, group, groupdir, search_text,
110 # pagesize, startwith 110 # pagesize, startwith
111
112 # list of network error codes that shouldn't be reported to tracker admin
113 # (error descriptions from FreeBSD intro(2))
114 IGNORE_NET_ERRORS = (
115 # A write on a pipe, socket or FIFO for which there is
116 # no process to read the data.
117 errno.EPIPE,
118 # A connection was forcibly closed by a peer.
119 # This normally results from a loss of the connection
120 # on the remote socket due to a timeout or a reboot.
121 errno.ECONNRESET,
122 # Software caused connection abort. A connection abort
123 # was caused internal to your host machine.
124 errno.ECONNABORTED,
125 # A connect or send request failed because the connected party
126 # did not properly respond after a period of time.
127 errno.ETIMEDOUT,
128 )
111 129
112 def __init__(self, instance, request, env, form=None, translator=None): 130 def __init__(self, instance, request, env, form=None, translator=None):
113 # re-seed the random number generator 131 # re-seed the random number generator
114 random.seed() 132 random.seed()
115 self.start = time.time() 133 self.start = time.time()
817 break 835 break
818 else: 836 else:
819 raise ValueError, 'No such action "%s"'%action_name 837 raise ValueError, 'No such action "%s"'%action_name
820 return action_klass 838 return action_klass
821 839
840 def _socket_op(self, call, *args, **kwargs):
841 """Execute socket-related operation, catch common network errors
842
843 Parameters:
844 call: a callable to execute
845 args, kwargs: call arguments
846
847 """
848 try:
849 call(*args, **kwargs)
850 except socket.error, err:
851 if err.errno not in self.IGNORE_NET_ERRORS:
852 raise
853
822 def write(self, content): 854 def write(self, content):
823 if not self.headers_done: 855 if not self.headers_done:
824 self.header() 856 self.header()
825 if self.env['REQUEST_METHOD'] != 'HEAD': 857 if self.env['REQUEST_METHOD'] != 'HEAD':
826 try: 858 self._socket_op(self.request.wfile.write, content)
827 self.request.wfile.write(content)
828 except socket.error, error:
829 # the end-user has gone away
830 if error.errno != errno.EPIPE:
831 raise
832 859
833 def write_html(self, content): 860 def write_html(self, content):
834 if not self.headers_done: 861 if not self.headers_done:
835 # at this point, we are sure about Content-Type 862 # at this point, we are sure about Content-Type
836 self.additional_headers['Content-Type'] = \ 863 self.additional_headers['Content-Type'] = \
845 # recode output 872 # recode output
846 content = content.decode(self.STORAGE_CHARSET, 'replace') 873 content = content.decode(self.STORAGE_CHARSET, 'replace')
847 content = content.encode(self.charset, 'xmlcharrefreplace') 874 content = content.encode(self.charset, 'xmlcharrefreplace')
848 875
849 # and write 876 # and write
850 try: 877 self._socket_op(self.request.wfile.write, content)
851 self.request.wfile.write(content)
852 except socket.error, error:
853 # the end-user has gone away
854 if error.errno != errno.EPIPE:
855 raise
856 878
857 def setHeader(self, header, value): 879 def setHeader(self, header, value):
858 '''Override a header to be returned to the user's browser. 880 '''Override a header to be returned to the user's browser.
859 ''' 881 '''
860 self.additional_headers[header] = value 882 self.additional_headers[header] = value
879 cookie = "%s=%s; Path=%s;"%(name, value, path) 901 cookie = "%s=%s; Path=%s;"%(name, value, path)
880 if expire is not None: 902 if expire is not None:
881 cookie += " expires=%s;"%Cookie._getdate(expire) 903 cookie += " expires=%s;"%Cookie._getdate(expire)
882 headers.append(('Set-Cookie', cookie)) 904 headers.append(('Set-Cookie', cookie))
883 905
884 self.request.start_response(headers, response) 906 self._socket_op(self.request.start_response, headers, response)
885 907
886 self.headers_done = 1 908 self.headers_done = 1
887 if self.debug: 909 if self.debug:
888 self.headers_sent = headers 910 self.headers_sent = headers
889 911

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