From 17802086f6c4ac846cdf5d9bfe8d4eb4908cc8ff Mon Sep 17 00:00:00 2001 From: Ivan Kolodyazhny Date: Tue, 6 Oct 2015 14:52:53 +0300 Subject: [PATCH] Fix Status-Line in HTTP response There is a strict rule about constructing status line for HTTP: '...Status-Line, consisting of the protocol version followed by a numeric status code and its associated textual phrase, with each element separated by SP characters' (http://www.faqs.org/rfcs/rfc2616.html) This patch coerces filling associated textual phrase. Also removed unused code from cinder/tests/unit/test_exception.py Change-Id: Ia9099fb5020cee02bfee2cd0e8e111845918c36c Closes-Bug: #1496055 Co-Authored-By: Marian Horban --- cinder/exception.py | 18 +++++++++- cinder/tests/unit/test_exception.py | 51 +++++++++++++---------------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/cinder/exception.py b/cinder/exception.py index 9367cae7185..2fed70b0b22 100644 --- a/cinder/exception.py +++ b/cinder/exception.py @@ -29,6 +29,8 @@ from oslo_log import log as logging from oslo_versionedobjects import exception as obj_exc import six import webob.exc +from webob.util import status_generic_reasons +from webob.util import status_reasons from cinder.i18n import _, _LE @@ -48,7 +50,21 @@ CONF.register_opts(exc_log_opts) class ConvertedException(webob.exc.WSGIHTTPException): def __init__(self, code=400, title="", explanation=""): self.code = code - self.title = title + # There is a strict rule about constructing status line for HTTP: + # '...Status-Line, consisting of the protocol version followed by a + # numeric status code and its associated textual phrase, with each + # element separated by SP characters' + # (http://www.faqs.org/rfcs/rfc2616.html) + # 'code' and 'title' can not be empty because they correspond + # to numeric status code and its associated text + if title: + self.title = title + else: + try: + self.title = status_reasons[self.code] + except KeyError: + generic_code = self.code // 100 + self.title = status_generic_reasons[generic_code] self.explanation = explanation super(ConvertedException, self).__init__() diff --git a/cinder/tests/unit/test_exception.py b/cinder/tests/unit/test_exception.py index ae2f0981a27..b8591b43599 100644 --- a/cinder/tests/unit/test_exception.py +++ b/cinder/tests/unit/test_exception.py @@ -18,36 +18,9 @@ from cinder import exception from cinder import test +import mock import six - - -class FakeNotifier(object): - """Acts like the cinder.openstack.common.notifier.api module.""" - ERROR = 88 - - def __init__(self): - self.provided_publisher = None - self.provided_event = None - self.provided_priority = None - self.provided_payload = None - - def notify(self, context, publisher, event, priority, payload): - self.provided_publisher = publisher - self.provided_event = event - self.provided_priority = priority - self.provided_payload = payload - - -def good_function(): - return 99 - - -def bad_function_error(): - raise exception.Error() - - -def bad_function_exception(): - raise test.TestingException() +import webob.util class CinderExceptionTestCase(test.TestCase): @@ -128,3 +101,23 @@ class CinderExceptionTestCase(test.TestCase): exc1 = Exception(msg) exc2 = FakeCinderException(message=exc1) self.assertEqual('Exception: test message', six.text_type(exc2)) + + +class CinderConvertedExceptionTestCase(test.TestCase): + def test_default_args(self): + exc = exception.ConvertedException() + self.assertNotEqual('', exc.title) + self.assertEqual(400, exc.code) + self.assertEqual('', exc.explanation) + + def test_standard_status_code(self): + with mock.patch.dict(webob.util.status_reasons, {200: 'reason'}): + exc = exception.ConvertedException(code=200) + self.assertEqual('reason', exc.title) + + @mock.patch.dict(webob.util.status_reasons, {500: 'reason'}) + def test_generic_status_code(self): + with mock.patch.dict(webob.util.status_generic_reasons, + {5: 'generic_reason'}): + exc = exception.ConvertedException(code=599) + self.assertEqual('generic_reason', exc.title)