Prevent HTML from appearing in API error messages

Currently if the request does not have an Accept header, all pecan
errors end up being HTML, which then gets wrapped into our standard
error format. This change prevents it.

Change-Id: I1968ab20fdeced852744fac5e0e795e997ae6e34
Story: #1662228
Task: #24869
This commit is contained in:
Dmitry Tantsur 2018-08-28 14:47:12 +02:00
parent ded9e7ce87
commit be09169c67
4 changed files with 25 additions and 2 deletions

View File

@ -64,6 +64,11 @@ class ParsableErrorMiddleware(object):
state['headers'] = headers state['headers'] = headers
return start_response(status, headers, exc_info) return start_response(status, headers, exc_info)
# The default for ironic is application/json. However, Pecan will try
# to output HTML errors if no Accept header is provided.
if 'HTTP_ACCEPT' not in environ or environ['HTTP_ACCEPT'] == '*/*':
environ['HTTP_ACCEPT'] = 'application/json'
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):
req = webob.Request(environ) req = webob.Request(environ)

View File

@ -400,8 +400,7 @@ class TestListPortgroups(test_api_base.BaseApiTest):
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: '1.23'}) headers={api_base.Version.string: '1.23'})
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
self.assertIn('The resource could not be found.', self.assertIn('Not Found', response.json['error_message'])
response.json['error_message'])
def test_ports_subresource_portgroup_not_found(self): def test_ports_subresource_portgroup_not_found(self):
non_existent_uuid = 'eeeeeeee-cccc-aaaa-bbbb-cccccccccccc' non_existent_uuid = 'eeeeeeee-cccc-aaaa-bbbb-cccccccccccc'

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from six.moves import http_client
from ironic.api.controllers.v1 import versions from ironic.api.controllers.v1 import versions
from ironic.tests.unit.api import base from ironic.tests.unit.api import base
@ -35,6 +37,18 @@ class TestRoot(base.BaseApiTest):
version1['min_version']) version1['min_version'])
self.assertEqual(versions.max_version_string(), version1['version']) self.assertEqual(versions.max_version_string(), version1['version'])
def test_no_html_errors(self):
response = self.get_json('/foo', expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int)
self.assertIn('Not Found', response.json['error_message'])
self.assertNotIn('<html', response.json['error_message'])
def test_no_html_errors2(self):
response = self.delete('/v1', expect_errors=True)
self.assertEqual(http_client.METHOD_NOT_ALLOWED, response.status_int)
self.assertIn('Not Allowed', response.json['error_message'])
self.assertNotIn('<html', response.json['error_message'])
class TestV1Root(base.BaseApiTest): class TestV1Root(base.BaseApiTest):

View File

@ -0,0 +1,5 @@
---
fixes:
- |
The bare metal API no longer returns HTML as part of the ``error_message``
field in error responses when no ``Accept`` header is provided.