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 webob
from xml import etree as et
from ceilometer.openstack.common import log
LOG = log.getLogger(__name__)
class ParsableErrorMiddleware(object):
@ -61,12 +67,24 @@ class ParsableErrorMiddleware(object):
app_iter = self.app(environ, replacement_start_response)
if (state['status_code'] / 100) not in (2, 3):
# FIXME(dhellmann): Always returns errors as JSON,
# but should look at the environ to determine
# the desired type.
body = [json.dumps({'error_message': '\n'.join(app_iter)})]
req = webob.Request(environ)
if (req.accept.best_match(['application/json', 'application/xml'])
== 'application/xml'):
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-Type', 'application/json'))
else:
body = app_iter
return body

View File

@ -26,6 +26,7 @@ from oslo.config import cfg
from ceilometer.api import app
from ceilometer.api import acl
from ceilometer import service
from .base import FunctionalTest
class TestApp(unittest.TestCase):
@ -50,3 +51,66 @@ class TestApp(unittest.TestCase):
api_app = app.setup_app()
self.assertEqual(api_app.auth_protocol, 'barttp')
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')