Eventlet green threads not released back to pool

Presently, the wsgi server allows persist connections. Hence even after
the response is sent to the client, it doesn't close the client socket
connection. Because of this problem, the green thread is not released
back to the pool.

In order to close the client socket connection explicitly after the
response is sent and read successfully by the client, you simply have to
set keepalive to False when you create a wsgi server.

DocImpact:
Added http_keepalive option (default=True).

SecurityImpact

Closes-Bug: #1361360
Change-Id: I93aaca24935a4f3096210233097dd6b8c5440176
This commit is contained in:
abhishekkekane 2014-10-21 04:39:59 -07:00 committed by Abhishek Kekane
parent 78b5b0a957
commit 16a821e00d
6 changed files with 56 additions and 2 deletions

View File

@ -1441,3 +1441,14 @@ return a ValueError exception with "No such digest method" error.
* ``digest_algorithm=<algorithm>``
Optional. Default: ``sha1``
Configuring http_keepalive option
----------------------------------
* ``http_keepalive=<True|False>``
If False, server will return the header "Connection: close", If True, server
will return "Connection: Keep-Alive" in its responses. In order to close the
client socket connection explicitly after the response is sent and read
successfully by the client, you simply have to set this option to False when
you create a wsgi server.

View File

@ -105,6 +105,13 @@ backlog = 4096
# represent the proxy's URL.
#public_endpoint=<None>
# http_keepalive option. If False, server will return the header
# "Connection: close", If True, server will return "Connection: Keep-Alive"
# in its responses. In order to close the client socket connection
# explicitly after the response is sent and read successfully by the client,
# you simply have to set this option to False when you create a wsgi server.
#http_keepalive = True
# ================= Syslog Options ============================
# Send logs to syslog (/dev/log) instead of to file specified

View File

@ -54,6 +54,13 @@ limit_param_default = 25
# Default: False
#sqlalchemy_debug = True
# http_keepalive option. If False, server will return the header
# "Connection: close", If True, server will return "Connection: Keep-Alive"
# in its responses. In order to close the client socket connection
# explicitly after the response is sent and read successfully by the client,
# you simply have to set this option to False when you create a wsgi server.
#http_keepalive = True
# ================= Syslog Options ============================
# Send logs to syslog (/dev/log) instead of to file specified

View File

@ -88,6 +88,9 @@ eventlet_opts = [
'max_header_line may need to be increased when using '
'large tokens (typically those generated by the '
'Keystone v3 API with big service catalogs')),
cfg.BoolOpt('http_keepalive', default=True,
help=_('If False, closes the client socket connection '
'explicitly.')),
]
profiler_opts = [
@ -344,7 +347,8 @@ class Server(object):
self.application,
log=self._wsgi_logger,
custom_pool=self.pool,
debug=False)
debug=False,
keepalive=CONF.http_keepalive)
except socket.error as err:
if err[0] != errno.EINVAL:
raise
@ -355,7 +359,8 @@ class Server(object):
LOG.info(_LI("Starting single process server"))
eventlet.wsgi.server(sock, application, custom_pool=self.pool,
log=self._wsgi_logger,
debug=False)
debug=False,
keepalive=CONF.http_keepalive)
class Middleware(object):

View File

@ -466,6 +466,28 @@ class ServerTest(test_utils.BaseTestCase):
actual = wsgi.Server(threads=1).create_pool()
self.assertIsInstance(actual, eventlet.greenpool.GreenPool)
@mock.patch.object(wsgi, 'get_socket')
def test_http_keepalive(self, mock_get_socket):
fake_socket = 'fake_socket'
mock_get_socket.return_value = 'fake_socket'
self.config(http_keepalive=False)
self.config(workers=0)
server = wsgi.Server(threads=1)
# mocking eventlet.wsgi server method to check it is called with
# configured 'http_keepalive' value.
with mock.patch.object(eventlet.wsgi,
'server') as mock_server:
fake_application = "fake-application"
server.start(fake_application, 0)
server.wait()
mock_server.assert_called_once_with(fake_socket,
fake_application,
log=server._wsgi_logger,
debug=False,
custom_pool=server.pool,
keepalive=False)
class TestHelpers(test_utils.BaseTestCase):

View File

@ -146,6 +146,7 @@ class OptsTestCase(utils.BaseTestCase):
'config_file',
'public_endpoint',
'digest_algorithm',
'http_keepalive',
]
self._check_opt_groups(opt_list, expected_opt_groups)
@ -207,6 +208,7 @@ class OptsTestCase(utils.BaseTestCase):
'flavor',
'config_file',
'digest_algorithm',
'http_keepalive',
]
self._check_opt_groups(opt_list, expected_opt_groups)