This commit is contained in:
Ryan Williams
2010-01-01 14:47:28 -08:00
5 changed files with 131 additions and 3 deletions

View File

@@ -23,6 +23,7 @@ Linden Lab Contributors
Thanks To
---------
* gholt, wsgi patches for accepting a custom pool, and returning 400 if content-length is invalid
* Luke Tucker, bug report regarding wsgi + webob
* Chuck Thier, reporting a bug in processes.py
* Brantley Harris, reporting bug #4

View File

@@ -33,6 +33,8 @@ def inject(module_name, new_globals, *additional_modules):
for name, mod in additional_modules:
if saved[name] is not None:
sys.modules[name] = saved[name]
else:
del sys.modules[name]
return module

View File

@@ -167,6 +167,17 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
if not self.parse_request():
return
content_length = self.headers.getheader('content-length')
if content_length:
try:
int(content_length)
except ValueError:
self.wfile.write(
"HTTP/1.0 400 Bad Request\r\n"
"Connection: close\r\nContent-length: 0\r\n\r\n")
self.close_connection = 1
return
self.environ = self.get_environ()
self.application = self.server.app
try:
@@ -423,7 +434,8 @@ def server(sock, site,
protocol=HttpProtocol,
server_event=None,
minimum_chunk_size=None,
log_x_forwarded_for=True):
log_x_forwarded_for=True,
custom_pool=None):
""" Start up a `WSGI <http://wsgi.org/wsgi/>`_ server handling requests from the supplied server
socket. This function loops forever.
@@ -449,7 +461,10 @@ def server(sock, site,
server_event.send(serv)
if max_size is None:
max_size = DEFAULT_MAX_SIMULTANEOUS_REQUESTS
pool = Pool(max_size=max_size)
if custom_pool is not None:
pool = custom_pool
else:
pool = Pool(max_size=max_size)
try:
host, port = sock.getsockname()
port = ':%s' % (port, )

72
tests/patcher_test.py Normal file
View File

@@ -0,0 +1,72 @@
import os
import tempfile
import subprocess
import sys
from tests import LimitedTestCase
base_module_contents = """
import socket
import urllib
print "base", socket, urllib
"""
patching_module_contents = """
from eventlet.green import socket
from eventlet.green import urllib
from eventlet import patcher
print 'patcher', socket, urllib
patcher.inject('%s', globals(), ('socket', socket), ('urllib', urllib))
del patcher
"""
import_module_contents = """
import %(mod)s
import httplib
print "importing", %(mod)s, httplib, %(mod)s.socket, %(mod)s.urllib
"""
class Patcher(LimitedTestCase):
TEST_TIMEOUT=3 # starting processes is time-consuming
def setUp(self):
self._saved_syspath = sys.path
self.tempfiles = []
def tearDown(self):
sys.path = self._saved_syspath
for tf in self.tempfiles:
os.remove(tf)
def write_to_tempfile(self, contents):
fn, filename = tempfile.mkstemp('_patcher_test.py')
fd = os.fdopen(fn, 'w')
fd.write(contents)
fd.close()
self.tempfiles.append(filename)
return os.path.dirname(filename), os.path.basename(filename)
def test_patch_a_module(self):
base = self.write_to_tempfile(base_module_contents)
base_modname = os.path.splitext(base[1])[0]
patching = self.write_to_tempfile(patching_module_contents % base_modname)
patching_modname = os.path.splitext(patching[1])[0]
importing = self.write_to_tempfile(
import_module_contents % dict(mod=patching_modname))
python_path = os.pathsep.join(sys.path)
python_path += os.pathsep.join((base[0], patching[0], importing[0]))
new_env = os.environ.copy()
new_env['PYTHONPATH'] = python_path
p = subprocess.Popen([sys.executable,
os.path.join(importing[0], importing[1])],
stdout=subprocess.PIPE, env=new_env)
output = p.communicate()
lines = output[0].split("\n")
self.assert_(lines[0].startswith('patcher'))
self.assert_(lines[1].startswith('base'))
self.assert_(lines[2].startswith('importing'))
self.assert_('eventlet.green.socket' in lines[1])
self.assert_('eventlet.green.urllib' in lines[1])
self.assert_('eventlet.green.socket' in lines[2])
self.assert_('eventlet.green.urllib' in lines[2])
self.assert_('eventlet.green.httplib' not in lines[2])

View File

@@ -490,7 +490,45 @@ class TestHttpd(LimitedTestCase):
'Connection: close\r\n'
'\r\n\r\n')
self.assert_('200 OK' in fd.read())
def test_022_custom_pool(self):
# just test that it accepts the parameter for now
# TODO: test that it uses the pool and that you can waitall() to
# ensure that all clients finished
from eventlet import pool
p = pool.Pool(max_size=5)
api.kill(self.killer)
listener = api.tcp_listener(('localhost', 0))
self.port = listener.getsockname()[1]
self.killer = api.spawn(
wsgi.server,
listener,
self.site,
max_size=128,
log=self.logfile,
custom_pool=p)
# this stuff is copied from test_001_server, could be better factored
sock = api.connect_tcp(
('localhost', self.port))
fd = sock.makeGreenFile()
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
result = fd.read()
fd.close()
self.assert_(result.startswith('HTTP'), result)
self.assert_(result.endswith('hello world'))
def test_023_bad_content_length(self):
sock = api.connect_tcp(
('localhost', self.port))
fd = sock.makeGreenFile()
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
result = fd.read()
fd.close()
self.assert_(result.startswith('HTTP'), result)
self.assert_('400 Bad Request' in result)
self.assert_('500' not in result)
if __name__ == '__main__':
main()