some fixes

This commit is contained in:
Benoit Chesneau 2010-01-16 03:20:11 +01:00
parent 5324d3cb60
commit 9900371813
5 changed files with 39 additions and 28 deletions

View File

@ -49,7 +49,7 @@ class Arbiter(object):
SIG_QUEUE = [] SIG_QUEUE = []
SIGNALS = map( SIGNALS = map(
lambda x: getattr(signal, "SIG%s" % x), lambda x: getattr(signal, "SIG%s" % x),
"CHLD HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCH".split() "HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCH".split()
) )
SIG_NAMES = dict( SIG_NAMES = dict(
(getattr(signal, name), name[3:].lower()) for name in dir(signal) (getattr(signal, name), name[3:].lower()) for name in dir(signal)
@ -74,6 +74,7 @@ class Arbiter(object):
map(self.set_non_blocking, pair) map(self.set_non_blocking, pair)
map(lambda p: fcntl.fcntl(p, fcntl.F_SETFD, fcntl.FD_CLOEXEC), pair) map(lambda p: fcntl.fcntl(p, fcntl.F_SETFD, fcntl.FD_CLOEXEC), pair)
map(lambda s: signal.signal(s, self.signal), self.SIGNALS) map(lambda s: signal.signal(s, self.signal), self.SIGNALS)
signal.signal(signal.SIGCHLD, self.handle_chld)
def set_non_blocking(self, fd): def set_non_blocking(self, fd):
flags = fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK flags = fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK
@ -170,7 +171,7 @@ class Arbiter(object):
log.info("Master is shutting down.") log.info("Master is shutting down.")
self.stop() self.stop()
def handle_chld(self): def handle_chld(self, sig, frame):
self.wakeup() self.wakeup()
def handle_hup(self): def handle_hup(self):

View File

@ -37,6 +37,8 @@ class HttpParser(object):
""" take a string buff. It return """ take a string buff. It return
environ or None if parsing isn't done. environ or None if parsing isn't done.
""" """
if self._headers:
return self._headers
# wee could be smarter here # wee could be smarter here
# by just reading the array, but converting # by just reading the array, but converting
@ -69,7 +71,7 @@ class HttpParser(object):
except ValueError: except ValueError:
# bad headers # bad headers
pass pass
headers = self._headers headers.update(self._headers)
self._content_len = int(self._headers.get('Content-Length') or 0) self._content_len = int(self._headers.get('Content-Length') or 0)
return headers return headers

View File

@ -55,7 +55,7 @@ class HTTPRequest(object):
SERVER_VERSION = "gunicorn/%s" % __version__ SERVER_VERSION = "gunicorn/%s" % __version__
def __init__(self, socket, client_address, server_address): def __init__(self, socket, client_address, server_address):
self.socket = socket self.socket = socket.dup()
self.client_address = client_address self.client_address = client_address
self.server_address = server_address self.server_address = server_address
self.response_status = None self.response_status = None
@ -69,12 +69,14 @@ class HTTPRequest(object):
remain = CHUNK_SIZE remain = CHUNK_SIZE
buf = create_string_buffer(remain) buf = create_string_buffer(remain)
remain -= self.socket.recv_into(buf, remain) remain -= self.socket.recv_into(buf, remain)
while not self.parser.headers(headers, buf): while not self.parser.headers(headers, buf):
data = create_string_buffer(remain) data = create_string_buffer(remain)
remain -= self.socket.recv_into(data, remain) remain -= self.socket.recv_into(data, remain)
buf = create_string_buffer(data.value + buf.value) buf = create_string_buffer(data.value + buf.value)
if headers.get('Accept', '').lower() == "100-continue": print headers
if headers.get('Except', '').lower() == "100-continue":
self.socket.send("100 Continue\n") self.socket.send("100 Continue\n")
if "?" in self.parser.path: if "?" in self.parser.path:

View File

@ -24,35 +24,41 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE. # OTHER DEALINGS IN THE SOFTWARE.
import time
from gunicorn.util import http_date from gunicorn.util import http_date
class HTTPResponse(object): class HTTPResponse(object):
def __init__(self, req, data): def __init__(self, sock, response, req):
self.req = req self.sock = sock
self.data = data self.data = response
self.headers = self.req.response_headers or {} self.headers = req.response_headers or {}
self.status = req.response_status
self.SERVER_VERSION = req.SERVER_VERSION
def send(self): def send(self):
# send headers # send headers
resp_head = [] resp_head = []
resp_head.append("%s %ss\r\n" % (self.req.parser.version, self.req.response_status)) resp_head.append("HTTP/1.1 %s\r\n" % (self.status))
resp_head.append("Server: %s\r\n" % self.req.SERVER_VERSION) resp_head.append("Server: %s\r\n" % self.SERVER_VERSION)
resp_head.append("Date: %s\r\n" % http_date()) resp_head.append("Date: %s\r\n" % http_date())
# broken clients # broken clients
resp_head.append("Status: %s\r\n" % str(self.req.response_status)) resp_head.append("Status: %s\r\n" % str(self.status))
# always close the conenction # always close the conenction
resp_head.append("Connection: close\r\n") resp_head.append("Connection: close\r\n")
for name, value in self.req.response_headers.items(): for name, value in self.headers.items():
resp_head.append("%s: %s\r\n" % (name, value)) resp_head.append("%s: %s\r\n" % (name, value))
self.req.socket.send("%s\r\n" % "".join(resp_head))
self.sock.send("%s\r\n" % "".join(resp_head))
for chunk in self.data: for chunk in self.data:
self.req.socket.send(chunk) self.sock.send(chunk)
self.req.socket.close() print "sent"
self.sock.close()
if hasattr(self.data, "close"): if hasattr(self.data, "close"):
self.data.close() self.data.close()

View File

@ -106,36 +106,36 @@ class Worker(object):
return return
raise raise
# Accept until we hit EAGAIN. We're betting that when we're # Accept until we hit EAGAIN. We're betting that when we're
# processing clients that more clients are waiting. When # processing clients that more clients are waiting. When
# there's no more clients waiting we go back to the select() # there's no more clients waiting we go back to the select()
# loop and wait for some lovin. # loop and wait for some lovin.
while self.alive: while self.alive:
#time.sleep(0.01)
try: try:
conn, addr = self.socket.accept() conn, addr = self.socket.accept()
conn.setblocking(1) conn.setblocking(1)
# handle connection
self.handle(conn, addr)
# Update the fd mtime on each client completion # Update the fd mtime on each client completion
# to signal that this worker process is alive. # to signal that this worker process is alive.
spinner = (spinner+1) % 2 spinner = (spinner+1) % 2
self._fchmod(spinner) self._fchmod(spinner)
# handle connection
self.handle(conn, addr)
except socket.error, e: except socket.error, e:
if e[0] in [errno.EAGAIN, errno.ECONNABORTED]: if e[0] in [errno.EAGAIN, errno.ECONNABORTED]:
break # Uh oh! break # Uh oh!
raise raise
def handle(self, conn, client): def handle(self, conn, client):
self.close_on_exec(conn) self.close_on_exec(conn)
try: try:
req = http.HTTPRequest(conn, client, self.address) req = http.HTTPRequest(conn, client, self.address)
result = self.app(req.read(), req.start_response) response = self.app(req.read(), req.start_response)
response = http.HTTPResponse(req, result) http.HTTPResponse(conn, response, req).send()
response.send()
except Exception, e: except Exception, e:
log.exception("Error processing request. [%s]" % str(e)) log.exception("Error processing request. [%s]" % str(e))
if e[0] == 32: if e[0] == 32: