send appropriate error status on http parsing. Fix issue #132.

This commit is contained in:
benoitc 2010-12-12 14:16:31 +01:00
parent b62055d529
commit a8e34ac16c
5 changed files with 52 additions and 31 deletions

View File

@ -45,7 +45,7 @@ hop_headers = set("""
te trailers transfer-encoding upgrade
server date
""".split())
try:
from setproctitle import setproctitle
def _setproctitle(title):
@ -178,27 +178,28 @@ def writelines(sock, lines, chunked=False):
for line in list(lines):
write(sock, line, chunked)
def write_error(sock, msg):
def write_error(sock, msg, status_int=500,
reason="Internal Server Error"):
html = textwrap.dedent("""\
<html>
<head>
<title>Internal Server Error</title>
<title>%(reason)s</title>
</head>
<body>
<h1>Internal Server Error</h1>
<h2>WSGI Error Report:</h2>
<pre>%s</pre>
<h1>%(reason)s</h1>
%(msg)s
</body>
</html>
""") % msg
""") % {"reason": reason, "msg": msg}
http = textwrap.dedent("""\
HTTP/1.1 500 Internal Server Error\r
HTTP/1.1 %s %s\r
Connection: close\r
Content-Type: text/html\r
Content-Length: %d\r
\r
%s
""") % (len(html), html)
""") % (str(status_int), reason, len(html), html)
write_nonblock(sock, http)
def normalize_name(name):

View File

@ -48,13 +48,7 @@ class AsyncWorker(base.Worker):
self.log.debug("Ignoring EPIPE")
except Exception, e:
self.log.exception("General error processing request.")
try:
# Last ditch attempt to notify the client of an error.
mesg = "HTTP/1.0 500 Internal Server Error\r\n\r\n"
util.write_nonblock(client, mesg)
except:
pass
return
self.handle_error(client, e)
finally:
util.close(client)
@ -82,9 +76,7 @@ class AsyncWorker(base.Worker):
raise
except Exception, e:
#Only send back traceback in HTTP in debug mode.
if not self.debug:
raise
util.write_error(sock, traceback.format_exc())
self.handle_error(sock, e)
return False
finally:
try:

View File

@ -10,10 +10,16 @@ import random
import signal
import sys
import tempfile
import traceback
from gunicorn import util
from gunicorn.workers.workertmp import WorkerTmp
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName, \
InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion
class Worker(object):
SIGNALS = map(
@ -110,6 +116,37 @@ class Worker(object):
self.alive = False
sys.exit(0)
def handle_error(self, client, exc):
if isinstance(exc, (InvalidRequestLine, InvalidRequestMethod,
InvalidHTTPVersion, InvalidHeader, InvalidHeaderName,)):
if isinstance(exc, InvalidRequestLine):
mesg = "<p>Invalid Request Line '%s'</p>" % str(exc)
elif isinstance(exc, InvalidRequestMethod):
mesg = "<p>Invalid Method'%s'</p>" % str(exc)
elif isinstance(exc, InvalidHTTPVersion):
mesg = "<p>Invalid HTTP Version '%s'</p>" % str(exc)
elif isinstance(exc, (InvalidHeaderName, InvalidHeader,)):
mesg = "<p>Invalid Header'%s'</p>" % str(exc)
reason = "Bad Request"
status_int = 400
else:
mesg = reason = "Internal Server reason"
status_int = 500
if self.debug:
tb = traceback.format_exc()
mesg += "<h2>Traceback:</23><pre>%s</pre>" % tb
try:
util.write_error(client, mesg, status_int=status_int,
reason=reason)
except:
self.log.warning("Unexpected error" % traceback.format_exc())
pass
def handle_winch(self, sig, fname):
# Ignore SIGWINCH in worker. Fixes a crash on OpenBSD.
return

View File

@ -72,7 +72,6 @@ class GeventWorker(AsyncWorker):
worker=self)
server.start()
try:
while self.alive:
self.notify()

View File

@ -8,7 +8,6 @@ import errno
import os
import select
import socket
import traceback
import gunicorn.http as http
import gunicorn.http.wsgi as wsgi
@ -63,7 +62,7 @@ class SyncWorker(base.Worker):
else:
return
raise
def handle(self, client, addr):
try:
parser = http.RequestParser(client)
@ -78,12 +77,7 @@ class SyncWorker(base.Worker):
self.log.debug("Ignoring EPIPE")
except Exception, e:
self.log.exception("Error processing request.")
try:
# Last ditch attempt to notify the client of an error.
mesg = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
util.write_nonblock(client, mesg)
except:
pass
self.handle_error(client, e)
finally:
util.close(client)
@ -111,9 +105,7 @@ class SyncWorker(base.Worker):
raise
except Exception, e:
# Only send back traceback in HTTP in debug mode.
if not self.debug:
raise
util.write_error(client, traceback.format_exc())
self.handle_error(client, e)
return
finally:
try: