wsgi: Allow minimum_chunk_size to be overriden on a per request basis

The application can set environ['eventlet.minimum_write_chunk_size']
which will override the minimum_chunk_size set on server initialization
for a single request.

https://bitbucket.org/eventlet/eventlet/pull-request/37/allow-minimum_chunk_size-to-be-overriden
This commit is contained in:
David Goetz
2013-05-01 15:32:09 -07:00
committed by Sergey Shepelev
parent 25bc2c402d
commit bc796c4f65
2 changed files with 66 additions and 2 deletions

View File

@@ -397,10 +397,12 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
towrite = []
towrite_size = 0
just_written_size = 0
minimum_write_chunk_size = int(self.environ.get(
'eventlet.minimum_write_chunk_size', self.minimum_chunk_size))
for data in result:
towrite.append(data)
towrite_size += len(data)
if towrite_size >= self.minimum_chunk_size:
if towrite_size >= minimum_write_chunk_size:
write(''.join(towrite))
towrite = []
just_written_size = towrite_size
@@ -640,7 +642,7 @@ def server(sock, site,
:param max_http_version: Set to "HTTP/1.0" to make the server pretend it only supports HTTP 1.0. This can help with applications or clients that don't behave properly using HTTP 1.1.
:param protocol: Protocol class. Deprecated.
:param server_event: Used to collect the Server object. Deprecated.
:param minimum_chunk_size: Minimum size in bytes for http chunks. This can be used to improve performance of applications which yield many small strings, though using it technically violates the WSGI spec.
:param minimum_chunk_size: Minimum size in bytes for http chunks. This can be used to improve performance of applications which yield many small strings, though using it technically violates the WSGI spec. This can be overridden on a per request basis by setting environ['eventlet.minimum_write_chunk_size'].
:param log_x_forwarded_for: If True (the default), logs the contents of the x-forwarded-for header in addition to the actual client ip address in the 'client_ip' field of the log line.
:param custom_pool: A custom GreenPool instance which is used to spawn client green threads. If this is supplied, max_size is ignored.
:param keepalive: If set to False, disables keepalives on the server; all connections will be closed after serving one request.

View File

@@ -1301,6 +1301,24 @@ class TestChunkedInput(_TestBase):
elif pi=="/ping":
input.read()
response.append("pong")
elif pi.startswith("/yield_spaces"):
if pi.endswith('override_min'):
env['eventlet.minimum_write_chunk_size'] = 1
self.yield_next_space = False
def response_iter():
yield ' '
num_sleeps = 0
while not self.yield_next_space and num_sleeps < 200:
eventlet.sleep(.01)
num_sleeps += 1
yield ' '
start_response('200 OK',
[('Content-Type', 'text/plain'),
('Content-Length', '2')])
return response_iter()
else:
raise RuntimeError("bad path")
@@ -1377,6 +1395,50 @@ class TestChunkedInput(_TestBase):
fd.sendall(req)
self.assertEquals(read_http(fd)[-1], 'this is chunked\nline 2\nline3')
def test_chunked_readline_wsgi_override_minimum_chunk_size(self):
fd = self.connect()
fd.sendall("POST /yield_spaces/override_min HTTP/1.1\r\nContent-Length: 0\r\n\r\n")
resp_so_far = ''
with eventlet.Timeout(.1):
while True:
one_byte = fd.recv(1)
resp_so_far += one_byte
if resp_so_far.endswith('\r\n\r\n'):
break
self.assertEquals(fd.recv(1), ' ')
try:
with eventlet.Timeout(.1):
fd.recv(1)
except eventlet.Timeout:
pass
else:
self.assert_(False)
self.yield_next_space = True
with eventlet.Timeout(.1):
self.assertEquals(fd.recv(1), ' ')
def test_chunked_readline_wsgi_not_override_minimum_chunk_size(self):
fd = self.connect()
fd.sendall("POST /yield_spaces HTTP/1.1\r\nContent-Length: 0\r\n\r\n")
resp_so_far = ''
try:
with eventlet.Timeout(.1):
while True:
one_byte = fd.recv(1)
resp_so_far += one_byte
if resp_so_far.endswith('\r\n\r\n'):
break
self.assertEquals(fd.recv(1), ' ')
except eventlet.Timeout:
pass
else:
self.assert_(False)
def test_close_before_finished(self):
import signal