enable xml error message response

return xml error message when Accept:application/xml request received.
default to json response when none specified.

Change-Id: Idd454c5bc76adb583bc0a9afce9f31659e7fe2ac
This commit is contained in:
Gordon Chung 2013-03-14 13:07:14 -04:00
parent 4abb407152
commit 31b88b87b9
2 changed files with 87 additions and 5 deletions

View File

@ -22,6 +22,12 @@ Based on pecan.middleware.errordocument
""" """
import json import json
import webob
from xml import etree as et
from ceilometer.openstack.common import log
LOG = log.getLogger(__name__)
class ParsableErrorMiddleware(object): class ParsableErrorMiddleware(object):
@ -61,12 +67,24 @@ class ParsableErrorMiddleware(object):
app_iter = self.app(environ, replacement_start_response) app_iter = self.app(environ, replacement_start_response)
if (state['status_code'] / 100) not in (2, 3): if (state['status_code'] / 100) not in (2, 3):
# FIXME(dhellmann): Always returns errors as JSON, req = webob.Request(environ)
# but should look at the environ to determine if (req.accept.best_match(['application/json', 'application/xml'])
# the desired type. == 'application/xml'):
body = [json.dumps({'error_message': '\n'.join(app_iter)})] try:
# simple check xml is valid
body = [et.ElementTree.tostring(
et.ElementTree.fromstring('<error_message>'
+ '\n'.join(app_iter)
+ '</error_message>'))]
except et.ElementTree.ParseError as err:
LOG.error('Error parsing HTTP response: %s' % err)
body = ['<error_message>%s' % state['status_code']
+ '</error_message>']
state['headers'].append(('Content-Type', 'application/xml'))
else:
body = [json.dumps({'error_message': '\n'.join(app_iter)})]
state['headers'].append(('Content-Type', 'application/json'))
state['headers'].append(('Content-Length', len(body[0]))) state['headers'].append(('Content-Length', len(body[0])))
state['headers'].append(('Content-Type', 'application/json'))
else: else:
body = app_iter body = app_iter
return body return body

View File

@ -26,6 +26,7 @@ from oslo.config import cfg
from ceilometer.api import app from ceilometer.api import app
from ceilometer.api import acl from ceilometer.api import acl
from ceilometer import service from ceilometer import service
from .base import FunctionalTest
class TestApp(unittest.TestCase): class TestApp(unittest.TestCase):
@ -50,3 +51,66 @@ class TestApp(unittest.TestCase):
api_app = app.setup_app() api_app = app.setup_app()
self.assertEqual(api_app.auth_protocol, 'barttp') self.assertEqual(api_app.auth_protocol, 'barttp')
os.unlink(tmpfile) os.unlink(tmpfile)
class TestApiMiddleware(FunctionalTest):
def test_json_parsable_error_middleware_404(self):
response = self.get_json('/invalid_path',
expect_errors=True,
headers={"Accept":
"application/json"}
)
self.assertEqual(response.status_int, 404)
self.assertEqual(response.content_type, "application/json")
self.assertTrue(response.json['error_message'])
response = self.get_json('/invalid_path',
expect_errors=True,
headers={"Accept":
"application/json,application/xml"}
)
self.assertEqual(response.status_int, 404)
self.assertEqual(response.content_type, "application/json")
self.assertTrue(response.json['error_message'])
response = self.get_json('/invalid_path',
expect_errors=True,
headers={"Accept":
"application/xml;q=0.8, \
application/json"}
)
self.assertEqual(response.status_int, 404)
self.assertEqual(response.content_type, "application/json")
self.assertTrue(response.json['error_message'])
response = self.get_json('/invalid_path',
expect_errors=True
)
self.assertEqual(response.status_int, 404)
self.assertEqual(response.content_type, "application/json")
self.assertTrue(response.json['error_message'])
response = self.get_json('/invalid_path',
expect_errors=True,
headers={"Accept":
"text/html,*/*"}
)
self.assertEqual(response.status_int, 404)
self.assertEqual(response.content_type, "application/json")
self.assertTrue(response.json['error_message'])
def test_xml_parsable_error_middleware_404(self):
response = self.get_json('/invalid_path',
expect_errors=True,
headers={"Accept":
"application/xml,*/*"}
)
self.assertEqual(response.status_int, 404)
self.assertEqual(response.content_type, "application/xml")
self.assertEqual(response.xml.tag, 'error_message')
response = self.get_json('/invalid_path',
expect_errors=True,
headers={"Accept":
"application/json;q=0.8 \
,application/xml"}
)
self.assertEqual(response.status_int, 404)
self.assertEqual(response.content_type, "application/xml")
self.assertEqual(response.xml.tag, 'error_message')