From 125a9a5587e1fbb115023c5ed74364af319f0154 Mon Sep 17 00:00:00 2001 From: Boris Pilka Date: Thu, 23 Aug 2018 16:51:58 +0200 Subject: [PATCH] Fix crash on Service catalog empty 403 response Added handling of message body received as bytes ("application/json") to avoid "TypeError: the JSON object must be str, not 'bytes'" Change-Id: I007b33e1b9f210ede2df5d1e2aa32535222d5d67 Task:24818 Story: 2003533 Signed-off-by: Boris Pilka --- magnumclient/common/httpclient.py | 58 ++++++++++++++++++------------- magnumclient/tests/utils.py | 7 ++++ 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/magnumclient/common/httpclient.py b/magnumclient/common/httpclient.py index 957cb17d..8e5d90f7 100644 --- a/magnumclient/common/httpclient.py +++ b/magnumclient/common/httpclient.py @@ -39,32 +39,42 @@ API_VERSION = '/v1' DEFAULT_API_VERSION = 'latest' -def _extract_error_json(body): - """Return error_message from the HTTP response body.""" +def _extract_error_json_text(body_json): error_json = {} - try: - body_json = json.loads(body) - if 'error_message' in body_json: - raw_msg = body_json['error_message'] - error_json = json.loads(raw_msg) - elif 'error' in body_json: - error_body = body_json['error'] - error_json = {'faultstring': error_body['title'], - 'debuginfo': error_body['message']} - else: - error_body = body_json['errors'][0] - error_json = {'faultstring': error_body['title']} - if 'detail' in error_body: - error_json['debuginfo'] = error_body['detail'] - elif 'description' in error_body: - error_json['debuginfo'] = error_body['description'] - - except ValueError: - return {} - + if 'error_message' in body_json: + raw_msg = body_json['error_message'] + error_json = json.loads(raw_msg) + elif 'error' in body_json: + error_body = body_json['error'] + error_json = {'faultstring': error_body['title'], + 'debuginfo': error_body['message']} + else: + error_body = body_json['errors'][0] + error_json = {'faultstring': error_body['title']} + if 'detail' in error_body: + error_json['debuginfo'] = error_body['detail'] + elif 'description' in error_body: + error_json['debuginfo'] = error_body['description'] return error_json +def _extract_error_json(body, resp): + """Return error_message from the HTTP response body.""" + content_type = resp.headers.get("Content-Type", "") + if content_type.startswith("application/json"): + try: + body_json = resp.json() + return _extract_error_json_text(body_json) + except ValueError: + return {} + else: + try: + body_json = json.loads(body) + return _extract_error_json_text(body_json) + except ValueError: + return {} + + class HTTPClient(object): def __init__(self, endpoint, api_version=DEFAULT_API_VERSION, **kwargs): @@ -200,7 +210,7 @@ class HTTPClient(object): if 400 <= resp.status < 600: LOG.warning("Request returned failure status.") - error_json = _extract_error_json(body_str) + error_json = _extract_error_json(body_str, resp) raise exceptions.from_response( resp, error_json.get('faultstring'), error_json.get('debuginfo'), method, url) @@ -346,7 +356,7 @@ class SessionClient(adapter.LegacyJsonAdapter): raise_exc=False, **kwargs) if 400 <= resp.status_code < 600: - error_json = _extract_error_json(resp.content) + error_json = _extract_error_json(resp.content, resp) raise exceptions.from_response( resp, error_json.get('faultstring'), error_json.get('debuginfo'), method, url) diff --git a/magnumclient/tests/utils.py b/magnumclient/tests/utils.py index 2ec6166b..c155ae01 100644 --- a/magnumclient/tests/utils.py +++ b/magnumclient/tests/utils.py @@ -15,6 +15,7 @@ import copy import datetime +import json as jsonlib import os import sys @@ -179,6 +180,12 @@ class FakeSessionResponse(object): self.content = content self.status_code = status_code + def json(self): + if self.content is not None: + return jsonlib.loads(self.content) + else: + return {} + class FakeSession(object):