mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
lot of fixes. nonblocking socket need to be handled correctly though.
This commit is contained in:
parent
7fccf32c06
commit
cb79c8514d
@ -99,6 +99,11 @@ class Arbiter(object):
|
||||
sock.setblocking(0)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
|
||||
if hasattr(socket, "TCP_CORK"):
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1)
|
||||
elif hasattr(socket, "TCP_NOPUSH"):
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NOPUSH, 1)
|
||||
sock.bind(address)
|
||||
sock.listen(2048)
|
||||
return sock
|
||||
|
||||
@ -22,20 +22,26 @@ from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \
|
||||
|
||||
import socket
|
||||
|
||||
SOCKET_CLOSED = (ECONNRESET, ENOTCONN, ESHUTDOWN)
|
||||
|
||||
class IOStream(object):
|
||||
|
||||
chunk_size = 4096
|
||||
|
||||
def __init__(self, sock):
|
||||
self.sock = sock
|
||||
self.sock = sock.dup()
|
||||
self.sock.setblocking(0)
|
||||
self.buf = ""
|
||||
|
||||
def recv(self, buffer_size):
|
||||
data = self.sock.recv(buffer_size)
|
||||
if not data:
|
||||
# we should handle close here
|
||||
return ''
|
||||
return data
|
||||
try:
|
||||
return self.sock.recv(buffer_size)
|
||||
except socket.error, e:
|
||||
if e[0] == EWOULDBLOCK:
|
||||
return None
|
||||
if e[0] in SOCKET_CLOSED:
|
||||
return ''
|
||||
raise
|
||||
|
||||
def send(self, data):
|
||||
return self.sock.send(data)
|
||||
|
||||
@ -20,9 +20,11 @@ import StringIO
|
||||
import sys
|
||||
from urllib import unquote
|
||||
|
||||
|
||||
from gunicorn import __version__
|
||||
from gunicorn.http.iostream import IOStream
|
||||
from gunicorn.util import http_date
|
||||
|
||||
|
||||
|
||||
NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
|
||||
|
||||
@ -54,6 +56,7 @@ class HTTPRequest(object):
|
||||
self._version = 11
|
||||
self.io = IOStream(socket)
|
||||
self.start_response_called = False
|
||||
self._should_close = False
|
||||
|
||||
def read(self):
|
||||
# read headers
|
||||
@ -130,6 +133,8 @@ class HTTPRequest(object):
|
||||
return None
|
||||
|
||||
def should_close(self):
|
||||
if self._should_close:
|
||||
return True
|
||||
if self.headers.get("CONNECTION") == "close":
|
||||
return True
|
||||
if self.headers.get("CONNECTION") == "Keep-Alive":
|
||||
@ -159,30 +164,22 @@ class HTTPRequest(object):
|
||||
data.seek(0)
|
||||
return data, str(length) or ""
|
||||
|
||||
|
||||
|
||||
def start_response(self, status, response_headers):
|
||||
self.start_response_called = True
|
||||
resp_head = []
|
||||
self.response_status = int(status.split(" ")[0])
|
||||
self.response_headers = {}
|
||||
resp_head.append("%s %ss\r\n" % (self.version, status))
|
||||
|
||||
resp_head.append("Server: %s\r\n" % self.SERVER_VERSION)
|
||||
resp_head.append("Date: %s\r\n" % http_date())
|
||||
# broken clients
|
||||
resp_head.append("Status: %s\r\n" % str(self.response_status))
|
||||
self.response_status = int(status.split(" ")[0])
|
||||
for name, value in response_headers:
|
||||
resp_head.append("%s: %s\r\n" % (_normalize_name(name), value.strip()))
|
||||
self.response_headers[name.lower()] = value
|
||||
self.io.send("%s\r\n" % "".join(resp_head))
|
||||
name = _normalize_name(name)
|
||||
self.response_headers[name] = value.strip()
|
||||
|
||||
self.start_response_called = True
|
||||
print "response called"
|
||||
|
||||
|
||||
def write(self, data):
|
||||
self.io.write(send)
|
||||
|
||||
def close(self):
|
||||
if self.should_close():
|
||||
self.socket.close()
|
||||
self.socket.close()
|
||||
|
||||
def first_line(self, line):
|
||||
method, path, version = line.strip().split(" ")
|
||||
@ -195,7 +192,7 @@ class HTTPRequest(object):
|
||||
name = name.strip().upper()
|
||||
self.headers[name] = value.strip()
|
||||
return name
|
||||
|
||||
|
||||
class FileInput(object):
|
||||
|
||||
stream_size = 4096
|
||||
@ -217,13 +214,14 @@ class FileInput(object):
|
||||
s = self._rbuf[:amt]
|
||||
self._rbuf = self._rbuf[amt:]
|
||||
return s
|
||||
|
||||
data = self.io.recv(amt)
|
||||
s = self._rbuf + data
|
||||
self._rbuf = ''
|
||||
print "return %s" % s
|
||||
return s
|
||||
|
||||
def readline(self, amt=-1):
|
||||
print "ici"
|
||||
i = self._rbuf.find('\n')
|
||||
while i < 0 and not (0 < amt <= len(self._rbuf)):
|
||||
new = self.io.recv(self.stream_size)
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
from gunicorn.util import http_date
|
||||
|
||||
class HTTPResponse(object):
|
||||
|
||||
@ -29,9 +29,23 @@ class HTTPResponse(object):
|
||||
self.io.send(data)
|
||||
|
||||
def send(self):
|
||||
if self.req.method == "HEAD":
|
||||
return
|
||||
# send headers
|
||||
resp_head = []
|
||||
resp_head.append("%s %ss\r\n" % (self.req.version, self.req.response_status))
|
||||
|
||||
resp_head.append("Server: %s\r\n" % self.req.SERVER_VERSION)
|
||||
resp_head.append("Date: %s\r\n" % http_date())
|
||||
# broken clients
|
||||
resp_head.append("Status: %s\r\n" % str(self.req.response_status))
|
||||
for name, value in self.req.response_headers.items():
|
||||
resp_head.append("%s: %s\r\n" % (name, value))
|
||||
self.io.send("%s\r\n" % "".join(resp_head))
|
||||
|
||||
|
||||
for chunk in self.data:
|
||||
self.write(chunk)
|
||||
self.data.close()
|
||||
self.req.close()
|
||||
|
||||
if hasattr(self.data, "close"):
|
||||
self.data.close()
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import errno
|
||||
import fcntl
|
||||
import logging
|
||||
import os
|
||||
import select
|
||||
@ -82,13 +83,11 @@ class Worker(object):
|
||||
break # Jump back to select
|
||||
raise # Uh oh!
|
||||
|
||||
conn.setblocking(1)
|
||||
conn.setblocking(0)
|
||||
try:
|
||||
self.handle(conn, addr)
|
||||
except:
|
||||
log.exception("Error processing request.")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
# Update the fd mtime on each client completion
|
||||
# to signal that this worker process is alive.
|
||||
@ -96,11 +95,8 @@ class Worker(object):
|
||||
os.fchmod(self.tmp.fileno(), spinner)
|
||||
|
||||
def handle(self, conn, client):
|
||||
while True:
|
||||
req = http.HTTPRequest(conn, client, self.address)
|
||||
result = self.app(req.read(), req.start_response)
|
||||
response = http.HTTPResponse(req, result)
|
||||
response.send()
|
||||
if req.should_close():
|
||||
conn.close()
|
||||
return
|
||||
fcntl.fcntl(conn.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
|
||||
req = http.HTTPRequest(conn, client, self.address)
|
||||
result = self.app(req.read(), req.start_response)
|
||||
response = http.HTTPResponse(req, result)
|
||||
response.send()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user