diff options
author | Sergey Shepelev <temotor@gmail.com> | 2015-09-07 04:23:47 +0300 |
---|---|---|
committer | Sergey Shepelev <temotor@gmail.com> | 2015-09-07 04:23:47 +0300 |
commit | b443de322aed2b0f9f0d1aab3d24c1f7cd5bd2da (patch) | |
tree | 63aa781379b46ae8f7b7ed8950454f97414c7ad6 | |
parent | 4f015c2993be7ed90177cd43780cd1423cc932a1 (diff) | |
download | eventlet-wsgi-drop-invalid.tar.gz |
wsgi: improved request body discardwsgi-drop-invalid
- 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
-rw-r--r-- | eventlet/wsgi.py | 40 | ||||
-rw-r--r-- | tests/wsgi_test.py | 8 |
2 files changed, 26 insertions, 22 deletions
diff --git a/eventlet/wsgi.py b/eventlet/wsgi.py index 4b5f38a..c0f1f24 100644 --- a/eventlet/wsgi.py +++ b/eventlet/wsgi.py @@ -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']: diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py index 4d67ede..00a5c45 100644 --- a/tests/wsgi_test.py +++ b/tests/wsgi_test.py @@ -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) |