Let error messages to be normal strings again

This changes how we decided to handle HTTPBadRequest and friends.
Previously, we came to forcing everything to be bytes, because
obviously WSGI bodies can only be bytes. But it turned out to
be too much hassle, so let's revisit that decision.

We aren't going to back-convert all the bytes bodies. That is
already too much hassle too. But this patch throws in a few
examples, just to showcase what this patch does.

Change-Id: I206a9611e7f348f49e5c2d0e677fed3b0739c167
This commit is contained in:
Pete Zaitcev 2018-09-11 17:59:11 -05:00
parent 4bdc9b003a
commit 791482675d
2 changed files with 22 additions and 19 deletions

View File

@ -139,12 +139,12 @@ def check_metadata(req, target_type):
continue
key = key[len(prefix):]
if not key:
return HTTPBadRequest(body=b'Metadata name cannot be empty',
return HTTPBadRequest(body='Metadata name cannot be empty',
request=req, content_type='text/plain')
bad_key = not check_utf8(wsgi_to_str(key))
bad_value = value and not check_utf8(wsgi_to_str(value))
if target_type in ('account', 'container') and (bad_key or bad_value):
return HTTPBadRequest(body=b'Metadata must be valid UTF-8',
return HTTPBadRequest(body='Metadata must be valid UTF-8',
request=req, content_type='text/plain')
meta_count += 1
meta_size += len(key) + len(value)
@ -160,11 +160,11 @@ def check_metadata(req, target_type):
request=req, content_type='text/plain')
if meta_count > MAX_META_COUNT:
return HTTPBadRequest(
body=b'Too many metadata items; max %d' % MAX_META_COUNT,
body='Too many metadata items; max %d' % MAX_META_COUNT,
request=req, content_type='text/plain')
if meta_size > MAX_META_OVERALL_SIZE:
return HTTPBadRequest(
body=b'Total metadata too large; max %d'
body='Total metadata too large; max %d'
% MAX_META_OVERALL_SIZE,
request=req, content_type='text/plain')
return None
@ -187,22 +187,22 @@ def check_object_creation(req, object_name):
ml = req.message_length()
except ValueError as e:
return HTTPBadRequest(request=req, content_type='text/plain',
body=str(e).encode('ascii'))
body=str(e))
except AttributeError as e:
return HTTPNotImplemented(request=req, content_type='text/plain',
body=str(e).encode('ascii'))
body=str(e))
if ml is not None and ml > MAX_FILE_SIZE:
return HTTPRequestEntityTooLarge(body=b'Your request is too large.',
return HTTPRequestEntityTooLarge(body='Your request is too large.',
request=req,
content_type='text/plain')
if req.content_length is None and \
req.headers.get('transfer-encoding') != 'chunked':
return HTTPLengthRequired(body=b'Missing Content-Length header.',
return HTTPLengthRequired(body='Missing Content-Length header.',
request=req,
content_type='text/plain')
if len(object_name) > MAX_OBJECT_NAME_LENGTH:
return HTTPBadRequest(body=b'Object name length of %d longer than %d' %
return HTTPBadRequest(body='Object name length of %d longer than %d' %
(len(object_name), MAX_OBJECT_NAME_LENGTH),
request=req, content_type='text/plain')
@ -217,7 +217,7 @@ def check_object_creation(req, object_name):
content_type='text/plain')
if not check_utf8(wsgi_to_str(req.headers['Content-Type'])):
return HTTPBadRequest(request=req, body=b'Invalid Content-Type',
return HTTPBadRequest(request=req, body='Invalid Content-Type',
content_type='text/plain')
return check_metadata(req, 'object')
@ -300,7 +300,7 @@ def valid_timestamp(request):
try:
return request.timestamp
except exceptions.InvalidTimestamp as e:
raise HTTPBadRequest(body=str(e).encode('ascii'), request=request,
raise HTTPBadRequest(body=str(e), request=request,
content_type='text/plain')
@ -325,13 +325,13 @@ def check_delete_headers(request):
except ValueError:
raise HTTPBadRequest(request=request,
content_type='text/plain',
body=b'Non-integer X-Delete-After')
body='Non-integer X-Delete-After')
actual_del_time = utils.normalize_delete_at_timestamp(
now + x_delete_after)
if int(actual_del_time) <= now:
raise HTTPBadRequest(request=request,
content_type='text/plain',
body=b'X-Delete-After in past')
body='X-Delete-After in past')
request.headers['x-delete-at'] = actual_del_time
del request.headers['x-delete-after']
@ -341,12 +341,12 @@ def check_delete_headers(request):
int(request.headers['x-delete-at'])))
except ValueError:
raise HTTPBadRequest(request=request, content_type='text/plain',
body=b'Non-integer X-Delete-At')
body='Non-integer X-Delete-At')
if x_delete_at <= now and not utils.config_true_value(
request.headers.get('x-backend-replication', 'f')):
raise HTTPBadRequest(request=request, content_type='text/plain',
body=b'X-Delete-At in past')
body='X-Delete-At in past')
return request
@ -407,19 +407,19 @@ def check_name_format(req, name, target_type):
if not name:
raise HTTPPreconditionFailed(
request=req,
body=b'%s name cannot be empty' % target_type)
body='%s name cannot be empty' % target_type)
if isinstance(name, six.text_type):
name = name.encode('utf-8')
if b'/' in name:
raise HTTPPreconditionFailed(
request=req,
body=b'%s name cannot contain slashes' % target_type)
body='%s name cannot contain slashes' % target_type)
return name
check_account_format = functools.partial(check_name_format,
target_type=b'Account')
target_type='Account')
check_container_format = functools.partial(check_name_format,
target_type=b'Container')
target_type='Container')
def valid_api_version(version):

View File

@ -1179,6 +1179,9 @@ class Response(object):
self._conditional_etag = conditional_etag
self.request = request
self._app_iter = None
# Allow error messages to come as natural strings on py3.
if isinstance(body, six.text_type):
body = body.encode('utf8')
self.body = body
self.app_iter = app_iter
self.response_iter = None