Make the wsgi server work, and it works really well, keepalives, http 1.1, yay
This commit is contained in:
@@ -156,7 +156,7 @@ class GreenSocket(object):
|
|||||||
self.sendcount = 0
|
self.sendcount = 0
|
||||||
self.recvcount = 0
|
self.recvcount = 0
|
||||||
self.recvbuffer = ''
|
self.recvbuffer = ''
|
||||||
self._closed = False
|
self.closed = False
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
fd = self.fd
|
fd = self.fd
|
||||||
@@ -173,9 +173,9 @@ class GreenSocket(object):
|
|||||||
return fn(*args, **kw)
|
return fn(*args, **kw)
|
||||||
|
|
||||||
def close(self, *args, **kw):
|
def close(self, *args, **kw):
|
||||||
if self._closed:
|
if self.closed:
|
||||||
return
|
return
|
||||||
self._closed = True
|
self.closed = True
|
||||||
fn = self.close = self.fd.close
|
fn = self.close = self.fd.close
|
||||||
try:
|
try:
|
||||||
res = fn(*args, **kw)
|
res = fn(*args, **kw)
|
||||||
@@ -272,15 +272,19 @@ class GreenFile(object):
|
|||||||
|
|
||||||
def __init__(self, fd):
|
def __init__(self, fd):
|
||||||
self.sock = fd
|
self.sock = fd
|
||||||
|
self.closed = False
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.sock.close()
|
self.sock.close()
|
||||||
|
self.closed = True
|
||||||
|
|
||||||
def fileno(self):
|
def fileno(self):
|
||||||
return self.sock.fileno()
|
return self.sock.fileno()
|
||||||
|
|
||||||
# TODO next
|
# TODO next
|
||||||
# TODO flush
|
|
||||||
|
def flush(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
return self.sock.sendall(data)
|
return self.sock.sendall(data)
|
||||||
|
@@ -26,6 +26,7 @@ THE SOFTWARE.
|
|||||||
import errno
|
import errno
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
import urllib
|
import urllib
|
||||||
import socket
|
import socket
|
||||||
import cStringIO
|
import cStringIO
|
||||||
@@ -35,8 +36,22 @@ import BaseHTTPServer
|
|||||||
from eventlet import api
|
from eventlet import api
|
||||||
from eventlet.httpdate import format_date_time
|
from eventlet.httpdate import format_date_time
|
||||||
|
|
||||||
class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|
||||||
|
|
||||||
|
class Input(object):
|
||||||
|
def __init__(self, rfile, content_length):
|
||||||
|
self.rfile = rfile
|
||||||
|
self.content_length = content_length
|
||||||
|
|
||||||
|
def read(self, length=None):
|
||||||
|
if length is None:
|
||||||
|
length = self.content_length
|
||||||
|
if length is None:
|
||||||
|
return ''
|
||||||
|
return self.rfile.read(length)
|
||||||
|
|
||||||
|
|
||||||
|
class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
|
protocol_version = 'HTTP/1.1'
|
||||||
def log_message(self, format, *args):
|
def log_message(self, format, *args):
|
||||||
self.server.log_message("%s - - [%s] %s" % (
|
self.server.log_message("%s - - [%s] %s" % (
|
||||||
self.address_string(),
|
self.address_string(),
|
||||||
@@ -71,8 +86,10 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
wfile = self.wfile
|
wfile = self.wfile
|
||||||
num_blocks = None
|
num_blocks = None
|
||||||
|
use_chunked = False
|
||||||
|
|
||||||
def write(data, _write=wfile.write):
|
def write(data, _write=wfile.write):
|
||||||
|
towrite = []
|
||||||
if not headers_set:
|
if not headers_set:
|
||||||
raise AssertionError("write() before start_response()")
|
raise AssertionError("write() before start_response()")
|
||||||
elif not headers_sent:
|
elif not headers_sent:
|
||||||
@@ -80,16 +97,24 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
headers_sent.append(1)
|
headers_sent.append(1)
|
||||||
for k, v in response_headers:
|
for k, v in response_headers:
|
||||||
header_dict[k.lower()] = k
|
header_dict[k.lower()] = k
|
||||||
_write('HTTP/1.0 %s\r\n' % status)
|
towrite.append('%s %s\r\n' % (self.protocol_version, status))
|
||||||
# send Date header?
|
# send Date header?
|
||||||
if 'date' not in header_dict:
|
if 'date' not in header_dict:
|
||||||
_write('Date: %s\r\n' % (format_date_time(time.time()),))
|
towrite.append('Date: %s\r\n' % (format_date_time(time.time()),))
|
||||||
if 'content-length' not in header_dict and num_blocks == 1:
|
if num_blocks == 1:
|
||||||
_write('Content-Length: %s\r\n' % (len(data),))
|
towrite.append('Content-Length: %s\r\n' % (len(data),))
|
||||||
|
elif use_chunked:
|
||||||
|
towrite.append('Transfer-Encoding: chunked\r\n')
|
||||||
for header in response_headers:
|
for header in response_headers:
|
||||||
_write('%s: %s\r\n' % header)
|
towrite.append('%s: %s\r\n' % header)
|
||||||
_write('\r\n')
|
towrite.append('\r\n')
|
||||||
_write(data)
|
|
||||||
|
if use_chunked:
|
||||||
|
## Write the chunked encoding
|
||||||
|
towrite.append("%x\r\n%s\r\n" % (len(data), data))
|
||||||
|
else:
|
||||||
|
towrite.append(data)
|
||||||
|
_write(''.join(towrite))
|
||||||
|
|
||||||
def start_request(status, response_headers, exc_info=None):
|
def start_request(status, response_headers, exc_info=None):
|
||||||
if exc_info:
|
if exc_info:
|
||||||
@@ -106,18 +131,48 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
headers_set[:] = [status, response_headers]
|
headers_set[:] = [status, response_headers]
|
||||||
return write
|
return write
|
||||||
|
|
||||||
result = self.server.app(self.environ, start_request)
|
try:
|
||||||
|
result = self.server.app(self.environ, start_request)
|
||||||
|
except Exception, e:
|
||||||
|
exc = traceback.format_exc()
|
||||||
|
if not headers_sent:
|
||||||
|
start_request("500 Internal Server Error", [('Content-type', 'text/plain')])
|
||||||
|
write(exc)
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
num_blocks = len(result)
|
num_blocks = len(result)
|
||||||
except (TypeError, AttributeError, NotImplementedError):
|
except (TypeError, AttributeError, NotImplementedError):
|
||||||
pass
|
if self.protocol_version == 'HTTP/1.1':
|
||||||
|
use_chunked = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for data in result:
|
towrite = []
|
||||||
if data:
|
try:
|
||||||
write(data)
|
for data in result:
|
||||||
|
if data:
|
||||||
|
towrite.append(data)
|
||||||
|
if reduce(
|
||||||
|
lambda x, y: x + y,
|
||||||
|
map(
|
||||||
|
lambda x: len(x), towrite)) > 4096:
|
||||||
|
write(''.join(towrite))
|
||||||
|
del towrite[:]
|
||||||
|
except Exception, e:
|
||||||
|
exc = traceback.format_exc()
|
||||||
|
if not headers_sent:
|
||||||
|
start_request("500 Internal Server Error", [('Content-type', 'text/plain')])
|
||||||
|
write(exc)
|
||||||
|
return
|
||||||
|
|
||||||
|
if towrite:
|
||||||
|
write(''.join(towrite))
|
||||||
|
if use_chunked:
|
||||||
|
wfile.write('0\r\n\r\n')
|
||||||
if not headers_sent:
|
if not headers_sent:
|
||||||
write('')
|
write('')
|
||||||
|
except Exception, e:
|
||||||
|
traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
if hasattr(result, 'close'):
|
if hasattr(result, 'close'):
|
||||||
result.close()
|
result.close()
|
||||||
@@ -150,6 +205,8 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
env['REMOTE_ADDR'] = self.client_address[0]
|
env['REMOTE_ADDR'] = self.client_address[0]
|
||||||
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
|
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
|
||||||
|
|
||||||
|
env['wsgi.input'] = Input(self.rfile, length)
|
||||||
|
|
||||||
for h in self.headers.headers:
|
for h in self.headers.headers:
|
||||||
k, v = h.split(':', 1)
|
k, v = h.split(':', 1)
|
||||||
k = k.replace('-', '_').upper()
|
k = k.replace('-', '_').upper()
|
||||||
@@ -165,10 +222,8 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
return env
|
return env
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
# Override SocketServer.StreamRequestHandler.finish because
|
BaseHTTPServer.BaseHTTPRequestHandler.finish(self)
|
||||||
# we only need to call close on the socket, not the makefile'd things
|
self.connection.close()
|
||||||
|
|
||||||
self.request.close()
|
|
||||||
|
|
||||||
|
|
||||||
class Server(BaseHTTPServer.HTTPServer):
|
class Server(BaseHTTPServer.HTTPServer):
|
||||||
@@ -186,7 +241,6 @@ class Server(BaseHTTPServer.HTTPServer):
|
|||||||
def get_environ(self):
|
def get_environ(self):
|
||||||
socket = self.socket
|
socket = self.socket
|
||||||
d = {
|
d = {
|
||||||
'wsgi.input': socket,
|
|
||||||
'wsgi.errors': sys.stderr,
|
'wsgi.errors': sys.stderr,
|
||||||
'wsgi.version': (1, 0),
|
'wsgi.version': (1, 0),
|
||||||
'wsgi.multithread': True,
|
'wsgi.multithread': True,
|
||||||
@@ -200,6 +254,7 @@ class Server(BaseHTTPServer.HTTPServer):
|
|||||||
|
|
||||||
def process_request(self, (socket, address)):
|
def process_request(self, (socket, address)):
|
||||||
proto = HttpProtocol(socket, address, self)
|
proto = HttpProtocol(socket, address, self)
|
||||||
|
proto.handle()
|
||||||
|
|
||||||
def log_message(self, message):
|
def log_message(self, message):
|
||||||
self.log.write(message + '\n')
|
self.log.write(message + '\n')
|
||||||
|
Reference in New Issue
Block a user