mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
send appropriate error status on http parsing. Fix issue #132.
This commit is contained in:
parent
b62055d529
commit
a8e34ac16c
@ -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):
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user