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

View File

@ -48,13 +48,7 @@ class AsyncWorker(base.Worker):
self.log.debug("Ignoring EPIPE") self.log.debug("Ignoring EPIPE")
except Exception, e: except Exception, e:
self.log.exception("General error processing request.") self.log.exception("General error processing request.")
try: self.handle_error(client, e)
# 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
finally: finally:
util.close(client) util.close(client)
@ -82,9 +76,7 @@ class AsyncWorker(base.Worker):
raise raise
except Exception, e: except Exception, e:
#Only send back traceback in HTTP in debug mode. #Only send back traceback in HTTP in debug mode.
if not self.debug: self.handle_error(sock, e)
raise
util.write_error(sock, traceback.format_exc())
return False return False
finally: finally:
try: try:

View File

@ -10,10 +10,16 @@ import random
import signal import signal
import sys import sys
import tempfile import tempfile
import traceback
from gunicorn import util from gunicorn import util
from gunicorn.workers.workertmp import WorkerTmp from gunicorn.workers.workertmp import WorkerTmp
from gunicorn.http.errors import InvalidHeader, InvalidHeaderName, \
InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion
class Worker(object): class Worker(object):
SIGNALS = map( SIGNALS = map(
@ -110,6 +116,37 @@ class Worker(object):
self.alive = False self.alive = False
sys.exit(0) 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): def handle_winch(self, sig, fname):
# Ignore SIGWINCH in worker. Fixes a crash on OpenBSD. # Ignore SIGWINCH in worker. Fixes a crash on OpenBSD.
return return

View File

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

View File

@ -8,7 +8,6 @@ import errno
import os import os
import select import select
import socket import socket
import traceback
import gunicorn.http as http import gunicorn.http as http
import gunicorn.http.wsgi as wsgi import gunicorn.http.wsgi as wsgi
@ -63,7 +62,7 @@ class SyncWorker(base.Worker):
else: else:
return return
raise raise
def handle(self, client, addr): def handle(self, client, addr):
try: try:
parser = http.RequestParser(client) parser = http.RequestParser(client)
@ -78,12 +77,7 @@ class SyncWorker(base.Worker):
self.log.debug("Ignoring EPIPE") self.log.debug("Ignoring EPIPE")
except Exception, e: except Exception, e:
self.log.exception("Error processing request.") self.log.exception("Error processing request.")
try: self.handle_error(client, e)
# 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
finally: finally:
util.close(client) util.close(client)
@ -111,9 +105,7 @@ class SyncWorker(base.Worker):
raise raise
except Exception, e: except Exception, e:
# Only send back traceback in HTTP in debug mode. # Only send back traceback in HTTP in debug mode.
if not self.debug: self.handle_error(client, e)
raise
util.write_error(client, traceback.format_exc())
return return
finally: finally:
try: try: