Skip to content

Commit 1bad98c

Browse files
committed
issue2550826 IOError in detector causes apache 'premature end of script headers' error
Capture all exceptions from auditors/reactors and raise a DetectorError instead. This allows failures like IOErrors from the detectors (e.g. unable to access files) to be handled. Previously an IOError just resulted in no output (premature end of headers under apache). Problem diagnosed and initial patch created by Tom Ekberg (tekberg). Patch application/mods and testing by rouilj.
1 parent a87545c commit 1bad98c

File tree

4 files changed

+48
-4
lines changed

4 files changed

+48
-4
lines changed

CHANGES.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ Fixed:
6969
- issue2550907 Fix errors when creating documentation. Work done by
7070
Peter Funk (pefu). (Applied by John Rouillard with small change
7171
omitting obsolete security.txt.)
72+
- issue2550826 Capture all exceptions from auditors/reactors and
73+
raise a DetectorError instead. This allows failures like IOErrors
74+
from the detectors (e.g. unable to access files) to be handled.
75+
Previously an IOError just resulted in no output (premature end of
76+
headers under apache). Problem diagnosed and initial patch created by
77+
Tom Ekberg (tekberg). Further testing and patch change done by
78+
John Rouillard.
7279

7380
2016-01-11: 1.5.1
7481

roundup/cgi/client.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from roundup.exceptions import LoginError, Reject, RejectRaw, Unauthorised
2020
from roundup.cgi.exceptions import (
2121
FormError, NotFound, NotModified, Redirect, SendFile, SendStaticFile,
22-
SeriousError)
22+
DetectorError, SeriousError)
2323
from roundup.cgi.form_parser import FormParser
2424
from roundup.mailer import Mailer, MessageSendError, encode_quopri
2525
from roundup.cgi import accept_language
@@ -572,6 +572,15 @@ def inner_main(self):
572572
# OpenSSL.SSL.SysCallError is similar to IOError above
573573
# may happen during write_html and serve_file, too.
574574
pass
575+
except DetectorError as e:
576+
if not self.instance.config.WEB_DEBUG:
577+
# run when we are not in debug mode, so errors
578+
# go to admin too.
579+
self.send_error_to_admin(e.subject, e.html, e.txt)
580+
self.write_html(e.html)
581+
else:
582+
# in debug mode, only write error to screen.
583+
self.write_html(e.html)
575584
except:
576585
# Something has gone badly wrong. Therefore, we should
577586
# make sure that the response code indicates failure.

roundup/cgi/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ class NotFound(HTTPException):
1818
class NotModified(HTTPException):
1919
pass
2020

21+
class DetectorError(Exception):
22+
"""Raised when a detector throws an exception.
23+
Contains details of the exception."""
24+
def __init__(self, subject, html, txt):
25+
self.subject = subject
26+
self.html = html
27+
self.txt = txt
28+
2129
class FormError(ValueError):
2230
"""An 'expected' exception occurred during form parsing.
2331

roundup/hyperdb.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121
__docformat__ = 'restructuredtext'
2222

2323
# standard python modules
24-
import os, re, shutil, weakref
24+
import os, re, shutil, sys, weakref
25+
import traceback
2526

2627
# roundup modules
2728
import date, password
2829
from support import ensureParentsExist, PrioList
2930
from roundup.i18n import _
31+
from roundup.cgi.exceptions import DetectorError
3032

3133
#
3234
# Types
@@ -1290,7 +1292,16 @@ def audit(self, event, detector, priority = 100):
12901292
def fireAuditors(self, event, nodeid, newvalues):
12911293
"""Fire all registered auditors"""
12921294
for prio, name, audit in self.auditors[event]:
1293-
audit(self.db, self, nodeid, newvalues)
1295+
try:
1296+
audit(self.db, self, nodeid, newvalues)
1297+
except Exception as e:
1298+
tb = traceback.format_exc()
1299+
html = ("<h1>Traceback</h1>" + str(tb).replace('\n', '<br>').
1300+
replace(' ', '&nbsp;'))
1301+
txt = 'Caught exception %s: %s\n%s' % (str(type(e)), e, tb)
1302+
exc_info = sys.exc_info()
1303+
subject = "Error: %s" % exc_info[1]
1304+
raise DetectorError(subject, html, txt)
12941305

12951306
def react(self, event, detector, priority = 100):
12961307
"""Register a reactor detector"""
@@ -1299,7 +1310,16 @@ def react(self, event, detector, priority = 100):
12991310
def fireReactors(self, event, nodeid, oldvalues):
13001311
"""Fire all registered reactors"""
13011312
for prio, name, react in self.reactors[event]:
1302-
react(self.db, self, nodeid, oldvalues)
1313+
try:
1314+
react(self.db, self, nodeid, oldvalues)
1315+
except Exception as e:
1316+
tb = traceback.format_exc()
1317+
html = ("<h1>Traceback</h1>" + str(tb).replace('\n', '<br>').
1318+
replace(' ', '&nbsp;'))
1319+
txt = 'Caught exception %s: %s\n%s' % (str(type(e)), e, tb)
1320+
exc_info = sys.exc_info()
1321+
subject = "Error: %s" % exc_info[1]
1322+
raise DetectorError(subject, html, txt)
13031323

13041324
#
13051325
# import / export support

0 commit comments

Comments
 (0)