Skip to content

Commit 43a43a5

Browse files
author
Alexander Smishlajev
committed
ignore common network errors, like "Connection reset by peer"
catch socket errors when sending http headers.
1 parent f10f7ed commit 43a43a5

File tree

1 file changed

+36
-14
lines changed

1 file changed

+36
-14
lines changed

roundup/cgi/client.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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 $
22

33
"""WWW request handler (also used in the stand-alone server).
44
"""
@@ -109,6 +109,24 @@ class Client:
109109
# columns, sort, sortdir, filter, group, groupdir, search_text,
110110
# pagesize, startwith
111111

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+
)
129+
112130
def __init__(self, instance, request, env, form=None, translator=None):
113131
# re-seed the random number generator
114132
random.seed()
@@ -819,16 +837,25 @@ def get_action_class(self, action_name):
819837
raise ValueError, 'No such action "%s"'%action_name
820838
return action_klass
821839

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+
822854
def write(self, content):
823855
if not self.headers_done:
824856
self.header()
825857
if self.env['REQUEST_METHOD'] != 'HEAD':
826-
try:
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
858+
self._socket_op(self.request.wfile.write, content)
832859

833860
def write_html(self, content):
834861
if not self.headers_done:
@@ -847,12 +874,7 @@ def write_html(self, content):
847874
content = content.encode(self.charset, 'xmlcharrefreplace')
848875

849876
# and write
850-
try:
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
877+
self._socket_op(self.request.wfile.write, content)
856878

857879
def setHeader(self, header, value):
858880
'''Override a header to be returned to the user's browser.
@@ -881,7 +903,7 @@ def header(self, headers=None, response=None):
881903
cookie += " expires=%s;"%Cookie._getdate(expire)
882904
headers.append(('Set-Cookie', cookie))
883905

884-
self.request.start_response(headers, response)
906+
self._socket_op(self.request.start_response, headers, response)
885907

886908
self.headers_done = 1
887909
if self.debug:

0 commit comments

Comments
 (0)