Wait for a non-empty chunk in WSGIContext._app_call
We're functioning as a WSGI server here, so this bit from PEP-3333 seems to apply: > The start_response callable must not actually transmit the response > headers. Instead, it must store them for the server or gateway to > transmit only after the first iteration of the application return > value that yields a non-empty bytestrin ... . In other words, response > headers must not be sent until there is actual body data available, or > until the application's returned iterable is exhausted. Plus, it mirrors what swob.Request.call_application does. Change-Id: I1e8501f8ce91ea912780db64fee1c56bef809a98
This commit is contained in:
@@ -42,7 +42,7 @@ from swift.common.swob import Request
|
|||||||
from swift.common.utils import capture_stdio, disable_fallocate, \
|
from swift.common.utils import capture_stdio, disable_fallocate, \
|
||||||
drop_privileges, get_logger, NullLogger, config_true_value, \
|
drop_privileges, get_logger, NullLogger, config_true_value, \
|
||||||
validate_configuration, get_hub, config_auto_int_value, \
|
validate_configuration, get_hub, config_auto_int_value, \
|
||||||
CloseableChain
|
reiterate
|
||||||
|
|
||||||
# Set maximum line size of message headers to be accepted.
|
# Set maximum line size of message headers to be accepted.
|
||||||
wsgi.MAX_HEADER_LINE = constraints.MAX_HEADER_SIZE
|
wsgi.MAX_HEADER_LINE = constraints.MAX_HEADER_SIZE
|
||||||
@@ -1053,16 +1053,11 @@ class WSGIContext(object):
|
|||||||
self._response_headers = None
|
self._response_headers = None
|
||||||
self._response_exc_info = None
|
self._response_exc_info = None
|
||||||
resp = self.app(env, self._start_response)
|
resp = self.app(env, self._start_response)
|
||||||
# if start_response has been called, just return the iter
|
# if start_response has not been called, iterate until we've got a
|
||||||
if self._response_status is not None:
|
# non-empty chunk, by which time the app *should* have called it
|
||||||
return resp
|
if self._response_status is None:
|
||||||
resp = iter(resp)
|
resp = reiterate(resp)
|
||||||
try:
|
return resp
|
||||||
first_chunk = next(resp)
|
|
||||||
except StopIteration:
|
|
||||||
return iter([])
|
|
||||||
else: # We got a first_chunk
|
|
||||||
return CloseableChain([first_chunk], resp)
|
|
||||||
|
|
||||||
def _get_status_int(self):
|
def _get_status_int(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1242,6 +1242,8 @@ class TestWSGIContext(unittest.TestCase):
|
|||||||
def test_app_iter_is_closable(self):
|
def test_app_iter_is_closable(self):
|
||||||
|
|
||||||
def app(env, start_response):
|
def app(env, start_response):
|
||||||
|
yield ''
|
||||||
|
yield ''
|
||||||
start_response('200 OK', [('Content-Length', '25')])
|
start_response('200 OK', [('Content-Length', '25')])
|
||||||
yield 'aaaaa'
|
yield 'aaaaa'
|
||||||
yield 'bbbbb'
|
yield 'bbbbb'
|
||||||
|
|||||||
Reference in New Issue
Block a user