diff --git a/doc/source/configuring.rst b/doc/source/configuring.rst index e3567cd7b5..67f8ec3382 100644 --- a/doc/source/configuring.rst +++ b/doc/source/configuring.rst @@ -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. diff --git a/etc/glance-api.conf b/etc/glance-api.conf index 3ab9b38569..7c9c2ebb38 100644 --- a/etc/glance-api.conf +++ b/etc/glance-api.conf @@ -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 diff --git a/etc/glance-registry.conf b/etc/glance-registry.conf index 45b95871a5..247a88ed3d 100644 --- a/etc/glance-registry.conf +++ b/etc/glance-registry.conf @@ -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 diff --git a/glance/common/wsgi.py b/glance/common/wsgi.py index 05307ab641..2b84a81b64 100644 --- a/glance/common/wsgi.py +++ b/glance/common/wsgi.py @@ -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): diff --git a/glance/tests/unit/common/test_wsgi.py b/glance/tests/unit/common/test_wsgi.py index f548a9045b..6908922e57 100644 --- a/glance/tests/unit/common/test_wsgi.py +++ b/glance/tests/unit/common/test_wsgi.py @@ -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): diff --git a/glance/tests/unit/test_opts.py b/glance/tests/unit/test_opts.py index d7243612fd..ca3a8dff1c 100644 --- a/glance/tests/unit/test_opts.py +++ b/glance/tests/unit/test_opts.py @@ -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)