wsgi: improved request body discard
- skip request body discarding when connection was to be closed anyway - handle ChunkReadError while discarding, write to log, close connection https://github.com/eventlet/eventlet/issues/27 https://github.com/eventlet/eventlet/issues/242
This commit is contained in:

committed by
Thomas Goirand

parent
d7caa5ee62
commit
6e82358e95
@@ -118,14 +118,12 @@ class Input(object):
|
||||
self.chunk_length = -1
|
||||
|
||||
def _do_read(self, reader, length=None):
|
||||
if self.wfile is not None and \
|
||||
not self.is_hundred_continue_response_sent:
|
||||
if self.wfile is not None and not self.is_hundred_continue_response_sent:
|
||||
# 100 Continue response
|
||||
self.send_hundred_continue_response()
|
||||
self.is_hundred_continue_response_sent = True
|
||||
if length is None and self.content_length is not None:
|
||||
length = self.content_length - self.position
|
||||
if length and length > self.content_length - self.position:
|
||||
if (self.content_length is not None) and (
|
||||
length is None or length > self.content_length - self.position):
|
||||
length = self.content_length - self.position
|
||||
if not length:
|
||||
return b''
|
||||
@@ -137,8 +135,7 @@ class Input(object):
|
||||
return read
|
||||
|
||||
def _chunked_read(self, rfile, length=None, use_readline=False):
|
||||
if self.wfile is not None and \
|
||||
not self.is_hundred_continue_response_sent:
|
||||
if self.wfile is not None and not self.is_hundred_continue_response_sent:
|
||||
# 100 Continue response
|
||||
self.send_hundred_continue_response()
|
||||
self.is_hundred_continue_response_sent = True
|
||||
@@ -223,6 +220,10 @@ class Input(object):
|
||||
for key, value in headers]
|
||||
self.hundred_continue_headers = headers
|
||||
|
||||
def discard(self, buffer_size=16 << 10):
|
||||
while self.read(buffer_size):
|
||||
pass
|
||||
|
||||
|
||||
class HeaderLineTooLong(Exception):
|
||||
pass
|
||||
@@ -245,6 +246,9 @@ class LoggerFileWrapper(object):
|
||||
self.log = log
|
||||
self._debug = debug
|
||||
|
||||
def error(self, msg, *args, **kwargs):
|
||||
self.write(msg, *args)
|
||||
|
||||
def info(self, msg, *args, **kwargs):
|
||||
self.write(msg, *args)
|
||||
|
||||
@@ -503,16 +507,20 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
finally:
|
||||
if hasattr(result, 'close'):
|
||||
result.close()
|
||||
if (self.environ['eventlet.input'].chunked_input or
|
||||
self.environ['eventlet.input'].position
|
||||
< (self.environ['eventlet.input'].content_length or 0)):
|
||||
request_input = self.environ['eventlet.input']
|
||||
if (request_input.chunked_input or
|
||||
request_input.position < (request_input.content_length or 0)):
|
||||
# Read and discard body if there was no pending 100-continue
|
||||
if not self.environ['eventlet.input'].wfile:
|
||||
# NOTE: MINIMUM_CHUNK_SIZE is used here for purpose different than chunking.
|
||||
# We use it only cause it's at hand and has reasonable value in terms of
|
||||
# emptying the buffer.
|
||||
while self.environ['eventlet.input'].read(MINIMUM_CHUNK_SIZE):
|
||||
pass
|
||||
if not request_input.wfile and self.close_connection == 0:
|
||||
try:
|
||||
request_input.discard()
|
||||
except ChunkReadError as e:
|
||||
self.close_connection = 1
|
||||
self.server.log.error((
|
||||
'chunked encoding error while discarding request body.'
|
||||
+ ' ip={0} request="{1}" error="{2}"').format(
|
||||
self.get_client_ip(), self.requestline, e,
|
||||
))
|
||||
finish = time.time()
|
||||
|
||||
for hook, args, kwargs in self.environ['eventlet.posthooks']:
|
||||
|
@@ -1638,7 +1638,6 @@ class ProxiedIterableAlreadyHandledTest(IterableAlreadyHandledTest):
|
||||
|
||||
|
||||
class TestChunkedInput(_TestBase):
|
||||
dirt = ""
|
||||
validator = None
|
||||
|
||||
def application(self, env, start_response):
|
||||
@@ -1687,16 +1686,13 @@ class TestChunkedInput(_TestBase):
|
||||
self.site = Site()
|
||||
self.site.application = self.application
|
||||
|
||||
def chunk_encode(self, chunks, dirt=None):
|
||||
if dirt is None:
|
||||
dirt = self.dirt
|
||||
|
||||
def chunk_encode(self, chunks, dirt=""):
|
||||
b = ""
|
||||
for c in chunks:
|
||||
b += "%x%s\r\n%s\r\n" % (len(c), dirt, c)
|
||||
return b
|
||||
|
||||
def body(self, dirt=None):
|
||||
def body(self, dirt=""):
|
||||
return self.chunk_encode(["this", " is ", "chunked", "\nline",
|
||||
" 2", "\n", "line3", ""], dirt=dirt)
|
||||
|
||||
|
Reference in New Issue
Block a user