Make proxy_logging close the WSGI iterator
PEP 333 says that the WSGI framework will call .close() on the iterator returned by a WSGI application once it's done, provided such a method exists. So, if our code wraps an iterator, then we have to call .close() on it once we're done with it. proxy_logging wasn't. Since WSGIContext gets it right, I looked at making proxy_logging use WSGIContext. However, WSGIContext is all about forcing the first chunk out of the iterator so that it can capture the final HTTP status and headers; it doesn't help if you want to look at every chunk. proxy_logging wants every chunk so it can count the bytes sent. This didn't hurt anything in Swift, but pconstantine was complaining in IRC that our failure to call .close() was goofing up some other middleware he had. Change-Id: Ic6ea0795ccef6cda2b5c6737697ef7d58eac9ab4
This commit is contained in:
parent
a6091c0f39
commit
db29ffc983
@ -289,6 +289,9 @@ class ProxyLoggingMiddleware(object):
|
||||
self.log_request(
|
||||
req, status_int, input_proxy.bytes_received, bytes_sent,
|
||||
start_time, time.time(), resp_headers=resp_headers)
|
||||
close_method = getattr(iterable, 'close', None)
|
||||
if callable(close_method):
|
||||
close_method()
|
||||
|
||||
try:
|
||||
iterable = self.app(env, my_start_response)
|
||||
|
@ -430,6 +430,27 @@ class TestProxyLogging(unittest.TestCase):
|
||||
self.assertEquals(log_parts[0], '1.2.3.4') # client ip
|
||||
self.assertEquals(log_parts[1], '1.2.3.4') # remote addr
|
||||
|
||||
def test_iterator_closing(self):
|
||||
|
||||
class CloseableBody(object):
|
||||
def __init__(self):
|
||||
self.closed = False
|
||||
|
||||
def close(self):
|
||||
self.closed = True
|
||||
|
||||
def __iter__(self):
|
||||
return iter(["CloseableBody"])
|
||||
|
||||
body = CloseableBody()
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(body), {})
|
||||
req = Request.blank('/', environ={'REQUEST_METHOD': 'GET',
|
||||
'REMOTE_ADDR': '1.2.3.4'})
|
||||
resp = app(req.environ, start_response)
|
||||
# exhaust generator
|
||||
[x for x in resp]
|
||||
self.assertTrue(body.closed)
|
||||
|
||||
def test_proxy_client_logging(self):
|
||||
app = proxy_logging.ProxyLoggingMiddleware(FakeApp(), {})
|
||||
app.access_logger = FakeLogger()
|
||||
|
Loading…
x
Reference in New Issue
Block a user