mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Fix PEP 333 compliance for the write callable.
This commit is contained in:
parent
e37bfa3c4e
commit
014d711bd7
@ -16,6 +16,7 @@ from urllib import unquote
|
||||
|
||||
from gunicorn import __version__
|
||||
from gunicorn.http.parser import Parser
|
||||
from gunicorn.http.response import Response
|
||||
from gunicorn.http.tee import TeeInput
|
||||
from gunicorn.util import CHUNK_SIZE
|
||||
|
||||
@ -43,7 +44,7 @@ class Request(object):
|
||||
def __init__(self, socket, client_address, server_address, conf):
|
||||
self.debug = conf['debug']
|
||||
self.conf = conf
|
||||
self._sock = socket
|
||||
self.socket = socket
|
||||
|
||||
self.client_address = client_address
|
||||
self.server_address = server_address
|
||||
@ -51,8 +52,8 @@ class Request(object):
|
||||
self.response_headers = []
|
||||
self._version = 11
|
||||
self.parser = Parser.parse_request()
|
||||
self.start_response_called = False
|
||||
self.log = logging.getLogger(__name__)
|
||||
self.response = None
|
||||
self.response_chunked = False
|
||||
self.headers_sent = False
|
||||
|
||||
@ -60,12 +61,12 @@ class Request(object):
|
||||
environ = {}
|
||||
headers = []
|
||||
buf = StringIO()
|
||||
data = self._sock.recv(CHUNK_SIZE)
|
||||
data = self.socket.recv(CHUNK_SIZE)
|
||||
buf.write(data)
|
||||
buf2 = self.parser.filter_headers(headers, buf)
|
||||
if not buf2:
|
||||
while True:
|
||||
data = self._sock.recv(CHUNK_SIZE)
|
||||
data = self.socket.recv(CHUNK_SIZE)
|
||||
if not data:
|
||||
break
|
||||
buf.write(data)
|
||||
@ -77,14 +78,14 @@ class Request(object):
|
||||
self.log.debug("Headers:\n%s" % headers)
|
||||
|
||||
if self.parser.headers_dict.get('Expect','').lower() == "100-continue":
|
||||
self._sock.send("HTTP/1.1 100 Continue\r\n\r\n")
|
||||
self.socket.send("HTTP/1.1 100 Continue\r\n\r\n")
|
||||
|
||||
if not self.parser.content_len and not self.parser.is_chunked:
|
||||
wsgi_input = TeeInput(self._sock, self.parser, StringIO(),
|
||||
wsgi_input = TeeInput(self.socket, self.parser, StringIO(),
|
||||
self.conf)
|
||||
content_length = "0"
|
||||
else:
|
||||
wsgi_input = TeeInput(self._sock, self.parser, buf2, self.conf)
|
||||
wsgi_input = TeeInput(self.socket, self.parser, buf2, self.conf)
|
||||
content_length = str(wsgi_input.len)
|
||||
|
||||
# This value should evaluate true if an equivalent application
|
||||
@ -154,23 +155,15 @@ class Request(object):
|
||||
environ[key] = value
|
||||
return environ
|
||||
|
||||
def start_response(self, status, response_headers, exc_info=None):
|
||||
def start_response(self, status, headers, exc_info=None):
|
||||
if exc_info:
|
||||
try:
|
||||
if self.headers_sent:
|
||||
if self.response and self.response.sent_headers:
|
||||
raise exc_info[0], exc_info[1], exc_info[2]
|
||||
finally:
|
||||
exc_info = None
|
||||
elif self.start_response_called:
|
||||
elif self.response is not None:
|
||||
raise AssertionError("Response headers already set!")
|
||||
|
||||
self.response_status = status
|
||||
for name, value in response_headers:
|
||||
if name.lower() == "transfer-encoding":
|
||||
if value.lower() == "chunked":
|
||||
self.response_chunked = True
|
||||
if not isinstance(value, basestring):
|
||||
value = str(value)
|
||||
self.response_headers.append((name.title(), value.strip()))
|
||||
|
||||
self.start_response_called = True
|
||||
self.response = Response(self, status, headers)
|
||||
return self.response.write
|
||||
|
||||
@ -3,43 +3,46 @@
|
||||
# This file is part of gunicorn released under the MIT license.
|
||||
# See the NOTICE for more information.
|
||||
|
||||
from gunicorn.util import http_date, write, write_chunk
|
||||
from gunicorn.util import close, http_date, write, write_chunk, is_hoppish
|
||||
|
||||
class Response(object):
|
||||
|
||||
def __init__(self, sock, response, req):
|
||||
def __init__(self, req, status, headers):
|
||||
self.req = req
|
||||
self._sock = sock
|
||||
self.data = response
|
||||
self.headers = req.response_headers or []
|
||||
self.status = req.response_status
|
||||
self.SERVER_VERSION = req.SERVER_VERSION
|
||||
self.chunked = req.response_chunked
|
||||
self.version = req.SERVER_VERSION
|
||||
self.status = status
|
||||
self.chunked = False
|
||||
self.headers = []
|
||||
self.headers_sent = False
|
||||
|
||||
def default_headers(self):
|
||||
return [
|
||||
"HTTP/1.1 %s\r\n" % self.status,
|
||||
"Server: %s\r\n" % self.SERVER_VERSION,
|
||||
for name, value in headers:
|
||||
assert isinstance(name, basestring), "%r is not a string" % name
|
||||
assert isinstance(value, basestring), "%r is not a string" % value
|
||||
assert not is_hoppish(name), "%s is a hop-by-hop header." % name
|
||||
if name.lower().strip() == "transfer-encoding":
|
||||
if value.lower().strip() == "chunked":
|
||||
self.chunked = True
|
||||
self.headers.append((name.strip(), value.strip()))
|
||||
|
||||
def send_headers(self):
|
||||
if self.headers_sent:
|
||||
return
|
||||
tosend = [
|
||||
"HTP/1.1 %s\r\n" % self.status,
|
||||
"Server: %s\r\n" % self.version,
|
||||
"Date: %s\r\n" % http_date(),
|
||||
"Connection: close\r\n"
|
||||
]
|
||||
tosend.extend(["%s: %s\r\n" % (n, v) for n, v in self.headers])
|
||||
write(self.req.socket, "%s\r\n" % "".join(tosend))
|
||||
self.headers_sent = True
|
||||
|
||||
def send(self):
|
||||
# send headers
|
||||
resp_head = self.default_headers()
|
||||
resp_head.extend(["%s: %s\r\n" % (n, v) for n, v in self.headers])
|
||||
write(self._sock, "%s\r\n" % "".join(resp_head))
|
||||
self.req.headers_sent = True
|
||||
|
||||
def write(self, arg):
|
||||
self.send_headers()
|
||||
assert isinstance(arg, basestring), "%r is not a string." % arg
|
||||
write(self.req.socket, arg, self.chunked)
|
||||
|
||||
last_chunk = None
|
||||
for chunk in self.data:
|
||||
last_chunk = chunk
|
||||
write(self._sock, chunk, self.chunked)
|
||||
|
||||
if self.chunked and last_chunk != "":
|
||||
# send last chunk
|
||||
write_chunk(self._sock, "")
|
||||
|
||||
if hasattr(self.data, "close"):
|
||||
self.data.close()
|
||||
def close(self):
|
||||
if self.chunked:
|
||||
write_chunk(self.socket, "")
|
||||
close(self.req.socket)
|
||||
|
||||
@ -29,6 +29,11 @@ weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||
monthname = [None,
|
||||
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
|
||||
hop_headers = set("""
|
||||
connection keep-alive proxy-authenticate proxy-authorization
|
||||
te trailers transfer-encoding upgrade
|
||||
""".split())
|
||||
|
||||
try:
|
||||
from setproctitle import setproctitle
|
||||
@ -202,3 +207,6 @@ def to_bytestring(s):
|
||||
return s.encode('utf-8')
|
||||
else:
|
||||
return s
|
||||
|
||||
def is_hoppish(header):
|
||||
return header.lower().strip() in hop_headers
|
||||
@ -158,7 +158,12 @@ class Worker(object):
|
||||
if not environ or not req.parser.status_line:
|
||||
return
|
||||
|
||||
response = self.app(environ, req.start_response)
|
||||
respiter = self.app(environ, req.start_response)
|
||||
for item in respiter:
|
||||
req.response.write(item)
|
||||
req.response.close()
|
||||
if hasattr(respiter, "close"):
|
||||
respiter.close()
|
||||
except Exception, e:
|
||||
# Only send back traceback in HTTP in debug mode.
|
||||
if not self.debug:
|
||||
@ -166,7 +171,6 @@ class Worker(object):
|
||||
util.write_error(client, traceback.format_exc())
|
||||
return
|
||||
|
||||
http.Response(client, response, req).send()
|
||||
except socket.error, e:
|
||||
if e[0] != errno.EPIPE:
|
||||
self.log.exception("Error processing request.")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user