diff --git a/bin/nova-api b/bin/nova-api index 16cf33cc5949..d957f3e58caa 100755 --- a/bin/nova-api +++ b/bin/nova-api @@ -54,6 +54,10 @@ if __name__ == '__main__': launcher = service.ProcessLauncher() for api in CONF.enabled_apis: should_use_ssl = api in CONF.enabled_ssl_apis - server = service.WSGIService(api, use_ssl=should_use_ssl) + if api == 'ec2': + server = service.WSGIService(api, use_ssl=should_use_ssl, + max_url_len=16384) + else: + server = service.WSGIService(api, use_ssl=should_use_ssl) launcher.launch_server(server, workers=server.workers or 1) launcher.wait() diff --git a/bin/nova-api-ec2 b/bin/nova-api-ec2 index c7b08845db26..d1b3d45eacde 100755 --- a/bin/nova-api-ec2 +++ b/bin/nova-api-ec2 @@ -41,6 +41,6 @@ if __name__ == '__main__': config.parse_args(sys.argv) logging.setup("nova") utils.monkey_patch() - server = service.WSGIService('ec2') + server = service.WSGIService('ec2', max_url_len=16384) service.serve(server, workers=server.workers) service.wait() diff --git a/nova/service.py b/nova/service.py index 87857f93d2f4..c250673f4694 100644 --- a/nova/service.py +++ b/nova/service.py @@ -574,7 +574,7 @@ class Service(object): class WSGIService(object): """Provides ability to launch API from a 'paste' configuration.""" - def __init__(self, name, loader=None, use_ssl=False): + def __init__(self, name, loader=None, use_ssl=False, max_url_len=None): """Initialize, but do not start the WSGI server. :param name: The name of the WSGI server given to the loader. @@ -594,7 +594,8 @@ class WSGIService(object): self.app, host=self.host, port=self.port, - use_ssl=self.use_ssl) + use_ssl=self.use_ssl, + max_url_len=max_url_len) # Pull back actual port used self.port = self.server.port self.backdoor_port = None diff --git a/nova/tests/test_wsgi.py b/nova/tests/test_wsgi.py index b04bc3e03c5a..cd64688a2266 100644 --- a/nova/tests/test_wsgi.py +++ b/nova/tests/test_wsgi.py @@ -22,6 +22,8 @@ import os.path import tempfile import eventlet +import httplib2 +import paste import nova.exception from nova import test @@ -108,6 +110,25 @@ class TestWSGIServer(test.TestCase): server.stop() server.wait() + def test_uri_length_limit(self): + server = nova.wsgi.Server("test_uri_length_limit", None, + host="127.0.0.1", max_url_len=16384) + server.start() + + uri = "http://127.0.0.1:%d/%s" % (server.port, 10000 * 'x') + resp, _ = httplib2.Http().request(uri) + eventlet.sleep(0) + self.assertNotEqual(resp.status, + paste.httpexceptions.HTTPRequestURITooLong.code) + + uri = "http://127.0.0.1:%d/%s" % (server.port, 20000 * 'x') + resp, _ = httplib2.Http().request(uri) + eventlet.sleep(0) + self.assertEqual(resp.status, + paste.httpexceptions.HTTPRequestURITooLong.code) + server.stop() + server.wait() + class TestWSGIServerWithSSL(test.TestCase): """WSGI server with SSL tests.""" diff --git a/nova/wsgi.py b/nova/wsgi.py index 0a7570b6c8da..651dbc4f64ab 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -75,7 +75,7 @@ class Server(object): def __init__(self, name, app, host='0.0.0.0', port=0, pool_size=None, protocol=eventlet.wsgi.HttpProtocol, backlog=128, - use_ssl=False): + use_ssl=False, max_url_len=None): """Initialize, but do not start, a WSGI server. :param name: Pretty name for logging. @@ -84,6 +84,7 @@ class Server(object): :param port: Port number to server the application. :param pool_size: Maximum number of eventlets to spawn concurrently. :param backlog: Maximum number of queued connections. + :param max_url_len: Maximum length of permitted URLs. :returns: None :raises: nova.exception.InvalidInput """ @@ -95,6 +96,7 @@ class Server(object): self._logger = logging.getLogger("nova.%s.wsgi.server" % self.name) self._wsgi_logger = logging.WritableLogger(self._logger) self._use_ssl = use_ssl + self._max_url_len = max_url_len if backlog < 1: raise exception.InvalidInput( @@ -177,13 +179,20 @@ class Server(object): ":%(port)s with SSL support") % self.__dict__) raise - self._server = eventlet.spawn(eventlet.wsgi.server, - self._socket, - self.app, - protocol=self._protocol, - custom_pool=self._pool, - log=self._wsgi_logger, - log_format=CONF.wsgi_log_format) + wsgi_kwargs = { + 'func': eventlet.wsgi.server, + 'sock': self._socket, + 'site': self.app, + 'protocol': self._protocol, + 'custom_pool': self._pool, + 'log': self._wsgi_logger, + 'log_format': CONF.wsgi_log_format + } + + if self._max_url_len: + wsgi_kwargs['url_length_limit'] = self._max_url_len + + self._server = eventlet.spawn(**wsgi_kwargs) def stop(self): """Stop this server.